rdbpython 0.2.1__cp39-cp39-macosx_11_0_arm64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- rdbpy/.dylibs/libbz2.1.0.8.dylib +0 -0
- rdbpy/.dylibs/liblz4.1.9.4.dylib +0 -0
- rdbpy/.dylibs/libsnappy.1.2.1.dylib +0 -0
- rdbpy/.dylibs/libz.1.3.1.dylib +0 -0
- rdbpy/.dylibs/libzstd.1.5.6.dylib +0 -0
- rdbpy/__init__.py +1 -0
- rdbpy/backup.pxd +35 -0
- rdbpy/cache.pxd +8 -0
- rdbpy/comparator.pxd +23 -0
- rdbpy/db.pxd +230 -0
- rdbpy/env.pxd +5 -0
- rdbpy/errors.py +26 -0
- rdbpy/filter_policy.pxd +39 -0
- rdbpy/include/rdb_include/comparator_wrapper.hpp +63 -0
- rdbpy/include/rdb_include/filter_policy_wrapper.hpp +89 -0
- rdbpy/include/rdb_include/memtable_factories.hpp +15 -0
- rdbpy/include/rdb_include/merge_operator_wrapper.hpp +132 -0
- rdbpy/include/rdb_include/slice_transform_wrapper.hpp +109 -0
- rdbpy/include/rdb_include/utils.hpp +8 -0
- rdbpy/include/rdb_include/write_batch_iter_helper.hpp +65 -0
- rdbpy/interfaces.py +77 -0
- rdbpy/iterator.pxd +16 -0
- rdbpy/lib_rocksdb.cpython-39-darwin.so +0 -0
- rdbpy/lib_rocksdb.pxd +768 -0
- rdbpy/lib_rocksdb.pyi +1465 -0
- rdbpy/lib_rocksdb.pyx +3221 -0
- rdbpy/lib_utils.py +52 -0
- rdbpy/logger.pxd +5 -0
- rdbpy/memtablerep.pxd +12 -0
- rdbpy/merge_operator.pxd +46 -0
- rdbpy/merge_operators.py +25 -0
- rdbpy/options.pxd +179 -0
- rdbpy/slice_.pxd +20 -0
- rdbpy/slice_transform.pxd +37 -0
- rdbpy/snapshot.pxd +3 -0
- rdbpy/status.pxd +15 -0
- rdbpy/std_memory.pxd +7 -0
- rdbpy/table_factory.pxd +50 -0
- rdbpy/transaction.pxd +154 -0
- rdbpy/universal_compaction.pxd +15 -0
- rdbpython-0.2.1.dist-info/METADATA +104 -0
- rdbpython-0.2.1.dist-info/RECORD +45 -0
- rdbpython-0.2.1.dist-info/WHEEL +5 -0
- rdbpython-0.2.1.dist-info/licenses/LICENSE.md +21 -0
- rdbpython-0.2.1.dist-info/top_level.txt +1 -0
rdbpy/lib_rocksdb.pyx
ADDED
|
@@ -0,0 +1,3221 @@
|
|
|
1
|
+
# distutils: language = c++
|
|
2
|
+
# distutils: language_level = 3
|
|
3
|
+
import cython
|
|
4
|
+
from libcpp.string cimport string
|
|
5
|
+
from libcpp.deque cimport deque
|
|
6
|
+
from libcpp.vector cimport vector
|
|
7
|
+
from cpython cimport bool as py_bool
|
|
8
|
+
from libcpp cimport bool as cpp_bool
|
|
9
|
+
from libc.stddef cimport size_t
|
|
10
|
+
from libc.stdint cimport uint32_t
|
|
11
|
+
from cython.operator cimport dereference as deref
|
|
12
|
+
from cpython.bytes cimport PyBytes_AsString
|
|
13
|
+
from cpython.bytes cimport PyBytes_Size
|
|
14
|
+
from cpython.bytes cimport PyBytes_FromString
|
|
15
|
+
from cpython.bytes cimport PyBytes_FromStringAndSize
|
|
16
|
+
from cpython.unicode cimport PyUnicode_Decode
|
|
17
|
+
|
|
18
|
+
from rdbpy.std_memory cimport shared_ptr
|
|
19
|
+
cimport rdbpy.options as options
|
|
20
|
+
cimport rdbpy.merge_operator as merge_operator
|
|
21
|
+
cimport rdbpy.filter_policy as filter_policy
|
|
22
|
+
cimport rdbpy.comparator as comparator
|
|
23
|
+
cimport rdbpy.slice_transform as slice_transform
|
|
24
|
+
cimport rdbpy.cache as cache
|
|
25
|
+
cimport rdbpy.logger as logger
|
|
26
|
+
cimport rdbpy.snapshot as snapshot
|
|
27
|
+
cimport rdbpy.db as db
|
|
28
|
+
cimport rdbpy.iterator as iterator
|
|
29
|
+
cimport rdbpy.backup as backup
|
|
30
|
+
cimport rdbpy.env as env
|
|
31
|
+
cimport rdbpy.transaction as transaction
|
|
32
|
+
cimport rdbpy.table_factory as table_factory
|
|
33
|
+
cimport rdbpy.memtablerep as memtablerep
|
|
34
|
+
cimport rdbpy.universal_compaction as universal_compaction
|
|
35
|
+
|
|
36
|
+
# Enums are the only exception for direct imports
|
|
37
|
+
# Their name als already unique enough
|
|
38
|
+
from rdbpy.universal_compaction cimport kCompactionStopStyleSimilarSize
|
|
39
|
+
from rdbpy.universal_compaction cimport kCompactionStopStyleTotalSize
|
|
40
|
+
|
|
41
|
+
from rdbpy.options cimport FlushOptions
|
|
42
|
+
from rdbpy.options cimport kCompactionStyleLevel
|
|
43
|
+
from rdbpy.options cimport kCompactionStyleUniversal
|
|
44
|
+
from rdbpy.options cimport kCompactionStyleFIFO
|
|
45
|
+
from rdbpy.options cimport kCompactionStyleNone
|
|
46
|
+
|
|
47
|
+
from rdbpy.slice_ cimport Slice
|
|
48
|
+
from rdbpy.status cimport Status
|
|
49
|
+
|
|
50
|
+
import sys
|
|
51
|
+
from rdbpy.interfaces import MergeOperator as IMergeOperator
|
|
52
|
+
from rdbpy.interfaces import AssociativeMergeOperator as IAssociativeMergeOperator
|
|
53
|
+
from rdbpy.interfaces import FilterPolicy as IFilterPolicy
|
|
54
|
+
from rdbpy.interfaces import Comparator as IComparator
|
|
55
|
+
from rdbpy.interfaces import SliceTransform as ISliceTransform
|
|
56
|
+
import traceback
|
|
57
|
+
import rdbpy.errors as errors
|
|
58
|
+
import weakref
|
|
59
|
+
|
|
60
|
+
# pxd defines:
|
|
61
|
+
# ctypedef const filter_policy.FilterPolicy ConstFilterPolicy
|
|
62
|
+
|
|
63
|
+
cdef extern from "rdb_include/utils.hpp" namespace "py_rocks":
|
|
64
|
+
cdef const Slice* vector_data(vector[Slice]&)
|
|
65
|
+
|
|
66
|
+
# Prepare python for threaded usage.
|
|
67
|
+
# Python callbacks (merge, comparator)
|
|
68
|
+
# could be executed in a rocksdb background thread (eg. compaction).
|
|
69
|
+
cdef extern from "Python.h":
|
|
70
|
+
void PyEval_InitThreads()
|
|
71
|
+
PyEval_InitThreads()
|
|
72
|
+
|
|
73
|
+
## Here comes the stuff to wrap the status to exception
|
|
74
|
+
cdef check_status(const Status& st):
|
|
75
|
+
if st.ok():
|
|
76
|
+
return
|
|
77
|
+
|
|
78
|
+
if st.IsNotFound():
|
|
79
|
+
raise errors.NotFound(st.ToString())
|
|
80
|
+
|
|
81
|
+
if st.IsCorruption():
|
|
82
|
+
raise errors.Corruption(st.ToString())
|
|
83
|
+
|
|
84
|
+
if st.IsNotSupported():
|
|
85
|
+
raise errors.NotSupported(st.ToString())
|
|
86
|
+
|
|
87
|
+
if st.IsInvalidArgument():
|
|
88
|
+
raise errors.InvalidArgument(st.ToString())
|
|
89
|
+
|
|
90
|
+
if st.IsIOError():
|
|
91
|
+
raise errors.RocksIOError(st.ToString())
|
|
92
|
+
|
|
93
|
+
if st.IsMergeInProgress():
|
|
94
|
+
raise errors.MergeInProgress(st.ToString())
|
|
95
|
+
|
|
96
|
+
if st.IsIncomplete():
|
|
97
|
+
raise errors.Incomplete(st.ToString())
|
|
98
|
+
|
|
99
|
+
raise Exception("Unknown error: %s" % st.ToString())
|
|
100
|
+
######################################################
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
cdef string bytes_to_string(path) except *:
|
|
104
|
+
return string(PyBytes_AsString(path), PyBytes_Size(path))
|
|
105
|
+
|
|
106
|
+
cdef string_to_bytes(string ob):
|
|
107
|
+
return PyBytes_FromStringAndSize(ob.c_str(), ob.size())
|
|
108
|
+
|
|
109
|
+
cdef Slice bytes_to_slice(ob) except *:
|
|
110
|
+
return Slice(PyBytes_AsString(ob), PyBytes_Size(ob))
|
|
111
|
+
|
|
112
|
+
cdef slice_to_bytes(Slice sl):
|
|
113
|
+
return PyBytes_FromStringAndSize(sl.data(), sl.size())
|
|
114
|
+
|
|
115
|
+
## only for filsystem paths
|
|
116
|
+
cdef string path_to_string(object path) except *:
|
|
117
|
+
if isinstance(path, bytes):
|
|
118
|
+
return bytes_to_string(path)
|
|
119
|
+
if isinstance(path, unicode):
|
|
120
|
+
path = path.encode(sys.getfilesystemencoding())
|
|
121
|
+
return bytes_to_string(path)
|
|
122
|
+
else:
|
|
123
|
+
raise TypeError("Wrong type for path: %s" % path)
|
|
124
|
+
|
|
125
|
+
cdef object string_to_path(string path):
|
|
126
|
+
fs_encoding = sys.getfilesystemencoding().encode('ascii')
|
|
127
|
+
return PyUnicode_Decode(path.c_str(), path.size(), fs_encoding, "replace")
|
|
128
|
+
|
|
129
|
+
## Here comes the stuff for the comparator
|
|
130
|
+
cdef class PyComparator(object):
|
|
131
|
+
cdef object get_ob(self):
|
|
132
|
+
return None
|
|
133
|
+
|
|
134
|
+
cdef const comparator.Comparator* get_comparator(self):
|
|
135
|
+
return NULL
|
|
136
|
+
|
|
137
|
+
cdef set_info_log(self, shared_ptr[logger.Logger] info_log):
|
|
138
|
+
pass
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
cdef class PyGenericComparator(PyComparator):
|
|
142
|
+
# pxd defines:
|
|
143
|
+
# cdef comparator.ComparatorWrapper* comparator_ptr
|
|
144
|
+
# cdef object ob
|
|
145
|
+
|
|
146
|
+
def __cinit__(self, object ob):
|
|
147
|
+
self.comparator_ptr = NULL
|
|
148
|
+
if not isinstance(ob, IComparator):
|
|
149
|
+
raise TypeError("%s is not of type %s" % (ob, IComparator))
|
|
150
|
+
|
|
151
|
+
self.ob = ob
|
|
152
|
+
self.comparator_ptr = new comparator.ComparatorWrapper(
|
|
153
|
+
bytes_to_string(ob.name()),
|
|
154
|
+
<void*>ob,
|
|
155
|
+
compare_callback)
|
|
156
|
+
|
|
157
|
+
def __dealloc__(self):
|
|
158
|
+
if not self.comparator_ptr == NULL:
|
|
159
|
+
del self.comparator_ptr
|
|
160
|
+
|
|
161
|
+
cdef object get_ob(self):
|
|
162
|
+
return self.ob
|
|
163
|
+
|
|
164
|
+
cdef const comparator.Comparator* get_comparator(self):
|
|
165
|
+
return <comparator.Comparator*> self.comparator_ptr
|
|
166
|
+
|
|
167
|
+
cdef set_info_log(self, shared_ptr[logger.Logger] info_log):
|
|
168
|
+
self.comparator_ptr.set_info_log(info_log)
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
cdef class PyBytewiseComparator(PyComparator):
|
|
172
|
+
# pxd defines:
|
|
173
|
+
# cdef const comparator.Comparator* comparator_ptr
|
|
174
|
+
|
|
175
|
+
def __cinit__(self):
|
|
176
|
+
self.comparator_ptr = comparator.BytewiseComparator()
|
|
177
|
+
|
|
178
|
+
cpdef name(self):
|
|
179
|
+
return PyBytes_FromString(self.comparator_ptr.Name())
|
|
180
|
+
|
|
181
|
+
cpdef compare(self, a, b):
|
|
182
|
+
return self.comparator_ptr.Compare(
|
|
183
|
+
bytes_to_slice(a),
|
|
184
|
+
bytes_to_slice(b))
|
|
185
|
+
|
|
186
|
+
cdef object get_ob(self):
|
|
187
|
+
return self
|
|
188
|
+
|
|
189
|
+
cdef const comparator.Comparator* get_comparator(self):
|
|
190
|
+
return self.comparator_ptr
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
cdef int compare_callback(
|
|
195
|
+
void* ctx,
|
|
196
|
+
logger.Logger* log,
|
|
197
|
+
string& error_msg,
|
|
198
|
+
const Slice& a,
|
|
199
|
+
const Slice& b) with gil:
|
|
200
|
+
|
|
201
|
+
try:
|
|
202
|
+
return (<object>ctx).compare(slice_to_bytes(a), slice_to_bytes(b))
|
|
203
|
+
except BaseException as error:
|
|
204
|
+
tb = traceback.format_exc()
|
|
205
|
+
logger.Log(log, "Error in compare callback: %s", <bytes>tb)
|
|
206
|
+
error_msg.assign(<bytes>str(error))
|
|
207
|
+
|
|
208
|
+
BytewiseComparator = PyBytewiseComparator
|
|
209
|
+
#########################################
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
## Here comes the stuff for the filter policy
|
|
214
|
+
cdef class PyFilterPolicy(object):
|
|
215
|
+
cdef object get_ob(self):
|
|
216
|
+
return None
|
|
217
|
+
|
|
218
|
+
cdef shared_ptr[ConstFilterPolicy] get_policy(self):
|
|
219
|
+
return shared_ptr[ConstFilterPolicy]()
|
|
220
|
+
|
|
221
|
+
cdef set_info_log(self, shared_ptr[logger.Logger] info_log):
|
|
222
|
+
pass
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
cdef class PyGenericFilterPolicy(PyFilterPolicy):
|
|
226
|
+
# pxd defines:
|
|
227
|
+
# cdef shared_ptr[filter_policy.FilterPolicyWrapper] policy
|
|
228
|
+
# cdef object ob
|
|
229
|
+
|
|
230
|
+
def __cinit__(self, object ob):
|
|
231
|
+
if not isinstance(ob, IFilterPolicy):
|
|
232
|
+
raise TypeError("%s is not of type %s" % (ob, IFilterPolicy))
|
|
233
|
+
|
|
234
|
+
self.ob = ob
|
|
235
|
+
self.policy.reset(new filter_policy.FilterPolicyWrapper(
|
|
236
|
+
bytes_to_string(ob.name()),
|
|
237
|
+
<void*>ob,
|
|
238
|
+
create_filter_callback,
|
|
239
|
+
key_may_match_callback))
|
|
240
|
+
|
|
241
|
+
cdef object get_ob(self):
|
|
242
|
+
return self.ob
|
|
243
|
+
|
|
244
|
+
cdef shared_ptr[ConstFilterPolicy] get_policy(self):
|
|
245
|
+
return <shared_ptr[ConstFilterPolicy]>(self.policy)
|
|
246
|
+
|
|
247
|
+
cdef set_info_log(self, shared_ptr[logger.Logger] info_log):
|
|
248
|
+
self.policy.get().set_info_log(info_log)
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
cdef void create_filter_callback(
|
|
252
|
+
void* ctx,
|
|
253
|
+
logger.Logger* log,
|
|
254
|
+
string& error_msg,
|
|
255
|
+
const Slice* keys,
|
|
256
|
+
int n,
|
|
257
|
+
string* dst) with gil:
|
|
258
|
+
|
|
259
|
+
try:
|
|
260
|
+
ret = (<object>ctx).create_filter(
|
|
261
|
+
[slice_to_bytes(keys[i]) for i in range(n)])
|
|
262
|
+
dst.append(bytes_to_string(ret))
|
|
263
|
+
except BaseException as error:
|
|
264
|
+
tb = traceback.format_exc()
|
|
265
|
+
logger.Log(log, "Error in create filter callback: %s", <bytes>tb)
|
|
266
|
+
error_msg.assign(<bytes>str(error))
|
|
267
|
+
|
|
268
|
+
cdef cpp_bool key_may_match_callback(
|
|
269
|
+
void* ctx,
|
|
270
|
+
logger.Logger* log,
|
|
271
|
+
string& error_msg,
|
|
272
|
+
const Slice& key,
|
|
273
|
+
const Slice& filt) with gil:
|
|
274
|
+
|
|
275
|
+
try:
|
|
276
|
+
return (<object>ctx).key_may_match(
|
|
277
|
+
slice_to_bytes(key),
|
|
278
|
+
slice_to_bytes(filt))
|
|
279
|
+
except BaseException as error:
|
|
280
|
+
tb = traceback.format_exc()
|
|
281
|
+
logger.Log(log, "Error in key_mach_match callback: %s", <bytes>tb)
|
|
282
|
+
error_msg.assign(<bytes>str(error))
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
cdef class PyBloomFilterPolicy(PyFilterPolicy):
|
|
286
|
+
# pxd defines:
|
|
287
|
+
# cdef shared_ptr[ConstFilterPolicy] policy
|
|
288
|
+
|
|
289
|
+
def __cinit__(self, int bits_per_key):
|
|
290
|
+
self.policy.reset(filter_policy.NewBloomFilterPolicy(bits_per_key))
|
|
291
|
+
|
|
292
|
+
cpdef name(self):
|
|
293
|
+
return PyBytes_FromString(self.policy.get().Name())
|
|
294
|
+
|
|
295
|
+
cpdef create_filter(self, keys):
|
|
296
|
+
cdef string dst
|
|
297
|
+
cdef vector[Slice] c_keys
|
|
298
|
+
|
|
299
|
+
for key in keys:
|
|
300
|
+
c_keys.push_back(bytes_to_slice(key))
|
|
301
|
+
|
|
302
|
+
self.policy.get().CreateFilter(
|
|
303
|
+
vector_data(c_keys),
|
|
304
|
+
<int>c_keys.size(),
|
|
305
|
+
cython.address(dst))
|
|
306
|
+
|
|
307
|
+
return string_to_bytes(dst)
|
|
308
|
+
|
|
309
|
+
cpdef key_may_match(self, key, filter_):
|
|
310
|
+
return self.policy.get().KeyMayMatch(
|
|
311
|
+
bytes_to_slice(key),
|
|
312
|
+
bytes_to_slice(filter_))
|
|
313
|
+
|
|
314
|
+
cdef object get_ob(self):
|
|
315
|
+
return self
|
|
316
|
+
|
|
317
|
+
cdef shared_ptr[ConstFilterPolicy] get_policy(self):
|
|
318
|
+
return self.policy
|
|
319
|
+
|
|
320
|
+
BloomFilterPolicy = PyBloomFilterPolicy
|
|
321
|
+
#############################################
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
## Here comes the stuff for the merge operator
|
|
326
|
+
cdef class PyMergeOperator(object):
|
|
327
|
+
# pxd defines:
|
|
328
|
+
# cdef shared_ptr[merge_operator.MergeOperator] merge_op
|
|
329
|
+
# cdef object ob
|
|
330
|
+
|
|
331
|
+
def __cinit__(self, object ob):
|
|
332
|
+
self.ob = ob
|
|
333
|
+
if isinstance(ob, IAssociativeMergeOperator):
|
|
334
|
+
self.merge_op.reset(
|
|
335
|
+
<merge_operator.MergeOperator*>
|
|
336
|
+
new merge_operator.AssociativeMergeOperatorWrapper(
|
|
337
|
+
bytes_to_string(ob.name()),
|
|
338
|
+
<void*>(ob),
|
|
339
|
+
merge_callback))
|
|
340
|
+
|
|
341
|
+
elif isinstance(ob, IMergeOperator):
|
|
342
|
+
self.merge_op.reset(
|
|
343
|
+
<merge_operator.MergeOperator*>
|
|
344
|
+
new merge_operator.MergeOperatorWrapper(
|
|
345
|
+
bytes_to_string(ob.name()),
|
|
346
|
+
<void*>ob,
|
|
347
|
+
<void*>ob,
|
|
348
|
+
full_merge_callback,
|
|
349
|
+
partial_merge_callback))
|
|
350
|
+
# elif isinstance(ob, str):
|
|
351
|
+
# if ob == "put":
|
|
352
|
+
# self.merge_op = merge_operator.MergeOperators.CreatePutOperator()
|
|
353
|
+
# elif ob == "put_v1":
|
|
354
|
+
# self.merge_op = merge_operator.MergeOperators.CreateDeprecatedPutOperator()
|
|
355
|
+
# elif ob == "uint64add":
|
|
356
|
+
# self.merge_op = merge_operator.MergeOperators.CreateUInt64AddOperator()
|
|
357
|
+
# elif ob == "stringappend":
|
|
358
|
+
# self.merge_op = merge_operator.MergeOperators.CreateStringAppendOperator()
|
|
359
|
+
# #TODO: necessary?
|
|
360
|
+
# # elif ob == "stringappendtest":
|
|
361
|
+
# # self.merge_op = merge_operator.MergeOperators.CreateStringAppendTESTOperator()
|
|
362
|
+
# elif ob == "max":
|
|
363
|
+
# self.merge_op = merge_operator.MergeOperators.CreateMaxOperator()
|
|
364
|
+
# else:
|
|
365
|
+
# msg = "{0} is not the default type".format(ob)
|
|
366
|
+
# raise TypeError(msg)
|
|
367
|
+
else:
|
|
368
|
+
msg = "%s is not of this types %s"
|
|
369
|
+
msg %= (ob, (IAssociativeMergeOperator, IMergeOperator))
|
|
370
|
+
raise TypeError(msg)
|
|
371
|
+
|
|
372
|
+
|
|
373
|
+
cdef object get_ob(self):
|
|
374
|
+
return self.ob
|
|
375
|
+
|
|
376
|
+
cdef shared_ptr[merge_operator.MergeOperator] get_operator(self):
|
|
377
|
+
return self.merge_op
|
|
378
|
+
|
|
379
|
+
cdef cpp_bool merge_callback(
|
|
380
|
+
void* ctx,
|
|
381
|
+
const Slice& key,
|
|
382
|
+
const Slice* existing_value,
|
|
383
|
+
const Slice& value,
|
|
384
|
+
string* new_value,
|
|
385
|
+
logger.Logger* log) with gil:
|
|
386
|
+
|
|
387
|
+
if existing_value == NULL:
|
|
388
|
+
py_existing_value = None
|
|
389
|
+
else:
|
|
390
|
+
py_existing_value = slice_to_bytes(deref(existing_value))
|
|
391
|
+
|
|
392
|
+
try:
|
|
393
|
+
ret = (<object>ctx).merge(
|
|
394
|
+
slice_to_bytes(key),
|
|
395
|
+
py_existing_value,
|
|
396
|
+
slice_to_bytes(value))
|
|
397
|
+
|
|
398
|
+
if ret[0]:
|
|
399
|
+
new_value.assign(bytes_to_string(ret[1]))
|
|
400
|
+
return True
|
|
401
|
+
return False
|
|
402
|
+
|
|
403
|
+
except:
|
|
404
|
+
tb = traceback.format_exc()
|
|
405
|
+
logger.Log(log, "Error in merge_callback: %s", <bytes>tb)
|
|
406
|
+
return False
|
|
407
|
+
|
|
408
|
+
cdef cpp_bool full_merge_callback(
|
|
409
|
+
void* ctx,
|
|
410
|
+
const Slice& key,
|
|
411
|
+
const Slice* existing_value,
|
|
412
|
+
const deque[string]& op_list,
|
|
413
|
+
string* new_value,
|
|
414
|
+
logger.Logger* log) with gil:
|
|
415
|
+
|
|
416
|
+
if existing_value == NULL:
|
|
417
|
+
py_existing_value = None
|
|
418
|
+
else:
|
|
419
|
+
py_existing_value = slice_to_bytes(deref(existing_value))
|
|
420
|
+
|
|
421
|
+
try:
|
|
422
|
+
ret = (<object>ctx).full_merge(
|
|
423
|
+
slice_to_bytes(key),
|
|
424
|
+
py_existing_value,
|
|
425
|
+
[string_to_bytes(op_list[i]) for i in range(op_list.size())])
|
|
426
|
+
|
|
427
|
+
if ret[0]:
|
|
428
|
+
new_value.assign(bytes_to_string(ret[1]))
|
|
429
|
+
return True
|
|
430
|
+
return False
|
|
431
|
+
|
|
432
|
+
except:
|
|
433
|
+
tb = traceback.format_exc()
|
|
434
|
+
logger.Log(log, "Error in full_merge_callback: %s", <bytes>tb)
|
|
435
|
+
return False
|
|
436
|
+
|
|
437
|
+
cdef cpp_bool partial_merge_callback(
|
|
438
|
+
void* ctx,
|
|
439
|
+
const Slice& key,
|
|
440
|
+
const Slice& left_op,
|
|
441
|
+
const Slice& right_op,
|
|
442
|
+
string* new_value,
|
|
443
|
+
logger.Logger* log) with gil:
|
|
444
|
+
|
|
445
|
+
try:
|
|
446
|
+
ret = (<object>ctx).partial_merge(
|
|
447
|
+
slice_to_bytes(key),
|
|
448
|
+
slice_to_bytes(left_op),
|
|
449
|
+
slice_to_bytes(right_op))
|
|
450
|
+
|
|
451
|
+
if ret[0]:
|
|
452
|
+
new_value.assign(bytes_to_string(ret[1]))
|
|
453
|
+
return True
|
|
454
|
+
return False
|
|
455
|
+
|
|
456
|
+
except:
|
|
457
|
+
tb = traceback.format_exc()
|
|
458
|
+
logger.Log(log, "Error in partial_merge_callback: %s", <bytes>tb)
|
|
459
|
+
return False
|
|
460
|
+
##############################################
|
|
461
|
+
|
|
462
|
+
#### Here comes the Cache stuff
|
|
463
|
+
cdef class PyCache(object):
|
|
464
|
+
cdef shared_ptr[cache.Cache] get_cache(self):
|
|
465
|
+
return shared_ptr[cache.Cache]()
|
|
466
|
+
|
|
467
|
+
|
|
468
|
+
cdef class PyLRUCache(PyCache):
|
|
469
|
+
# pxd defines:
|
|
470
|
+
# cdef shared_ptr[cache.Cache] cache_ob
|
|
471
|
+
|
|
472
|
+
def __cinit__(self, capacity, shard_bits=None):
|
|
473
|
+
if shard_bits is not None:
|
|
474
|
+
self.cache_ob = cache.NewLRUCache(capacity, shard_bits)
|
|
475
|
+
else:
|
|
476
|
+
self.cache_ob = cache.NewLRUCache(capacity)
|
|
477
|
+
|
|
478
|
+
cdef shared_ptr[cache.Cache] get_cache(self):
|
|
479
|
+
return self.cache_ob
|
|
480
|
+
|
|
481
|
+
LRUCache = PyLRUCache
|
|
482
|
+
###############################
|
|
483
|
+
|
|
484
|
+
### Here comes the stuff for SliceTransform
|
|
485
|
+
cdef class PySliceTransform(object):
|
|
486
|
+
# pxd defines:
|
|
487
|
+
# cdef shared_ptr[slice_transform.SliceTransform] transfomer
|
|
488
|
+
# cdef object ob
|
|
489
|
+
|
|
490
|
+
def __cinit__(self, object ob):
|
|
491
|
+
if not isinstance(ob, ISliceTransform):
|
|
492
|
+
raise TypeError("%s is not of type %s" % (ob, ISliceTransform))
|
|
493
|
+
|
|
494
|
+
self.ob = ob
|
|
495
|
+
self.transfomer.reset(
|
|
496
|
+
<slice_transform.SliceTransform*>
|
|
497
|
+
new slice_transform.SliceTransformWrapper(
|
|
498
|
+
bytes_to_string(ob.name()),
|
|
499
|
+
<void*>ob,
|
|
500
|
+
slice_transform_callback,
|
|
501
|
+
slice_in_domain_callback,
|
|
502
|
+
slice_in_range_callback))
|
|
503
|
+
|
|
504
|
+
cdef object get_ob(self):
|
|
505
|
+
return self.ob
|
|
506
|
+
|
|
507
|
+
cdef shared_ptr[slice_transform.SliceTransform] get_transformer(self):
|
|
508
|
+
return self.transfomer
|
|
509
|
+
|
|
510
|
+
cdef set_info_log(self, shared_ptr[logger.Logger] info_log):
|
|
511
|
+
cdef slice_transform.SliceTransformWrapper* ptr
|
|
512
|
+
ptr = <slice_transform.SliceTransformWrapper*> self.transfomer.get()
|
|
513
|
+
ptr.set_info_log(info_log)
|
|
514
|
+
|
|
515
|
+
|
|
516
|
+
cdef Slice slice_transform_callback(
|
|
517
|
+
void* ctx,
|
|
518
|
+
logger.Logger* log,
|
|
519
|
+
string& error_msg,
|
|
520
|
+
const Slice& src) with gil:
|
|
521
|
+
|
|
522
|
+
cdef size_t offset
|
|
523
|
+
cdef size_t size
|
|
524
|
+
|
|
525
|
+
try:
|
|
526
|
+
ret = (<object>ctx).transform(slice_to_bytes(src))
|
|
527
|
+
offset = ret[0]
|
|
528
|
+
size = ret[1]
|
|
529
|
+
if (offset + size) > src.size():
|
|
530
|
+
msg = "offset(%i) + size(%i) is bigger than slice(%i)"
|
|
531
|
+
raise Exception(msg % (offset, size, src.size()))
|
|
532
|
+
|
|
533
|
+
return Slice(src.data() + offset, size)
|
|
534
|
+
except BaseException as error:
|
|
535
|
+
tb = traceback.format_exc()
|
|
536
|
+
logger.Log(log, "Error in slice transfrom callback: %s", <bytes>tb)
|
|
537
|
+
error_msg.assign(<bytes>str(error))
|
|
538
|
+
|
|
539
|
+
cdef cpp_bool slice_in_domain_callback(
|
|
540
|
+
void* ctx,
|
|
541
|
+
logger.Logger* log,
|
|
542
|
+
string& error_msg,
|
|
543
|
+
const Slice& src) with gil:
|
|
544
|
+
|
|
545
|
+
try:
|
|
546
|
+
return (<object>ctx).in_domain(slice_to_bytes(src))
|
|
547
|
+
except BaseException as error:
|
|
548
|
+
tb = traceback.format_exc()
|
|
549
|
+
logger.Log(log, "Error in slice transfrom callback: %s", <bytes>tb)
|
|
550
|
+
error_msg.assign(<bytes>str(error))
|
|
551
|
+
|
|
552
|
+
cdef cpp_bool slice_in_range_callback(
|
|
553
|
+
void* ctx,
|
|
554
|
+
logger.Logger* log,
|
|
555
|
+
string& error_msg,
|
|
556
|
+
const Slice& src) with gil:
|
|
557
|
+
|
|
558
|
+
try:
|
|
559
|
+
return (<object>ctx).in_range(slice_to_bytes(src))
|
|
560
|
+
except BaseException as error:
|
|
561
|
+
tb = traceback.format_exc()
|
|
562
|
+
logger.Log(log, "Error in slice transfrom callback: %s", <bytes>tb)
|
|
563
|
+
error_msg.assign(<bytes>str(error))
|
|
564
|
+
###########################################
|
|
565
|
+
|
|
566
|
+
|
|
567
|
+
## Here are the TableFactories
|
|
568
|
+
cdef class PyTableFactory(object):
|
|
569
|
+
# pxd defines:
|
|
570
|
+
# cdef shared_ptr[table_factory.TableFactory] factory
|
|
571
|
+
|
|
572
|
+
cdef shared_ptr[table_factory.TableFactory] get_table_factory(self):
|
|
573
|
+
return self.factory
|
|
574
|
+
|
|
575
|
+
cdef set_info_log(self, shared_ptr[logger.Logger] info_log):
|
|
576
|
+
pass
|
|
577
|
+
|
|
578
|
+
|
|
579
|
+
cdef class BlockBasedTableFactory(PyTableFactory):
|
|
580
|
+
# pxd defines:
|
|
581
|
+
# cdef PyFilterPolicy py_filter_policy
|
|
582
|
+
|
|
583
|
+
def __init__(self,
|
|
584
|
+
index_type='binary_search',
|
|
585
|
+
py_bool hash_index_allow_collision=True,
|
|
586
|
+
checksum='crc32',
|
|
587
|
+
PyCache block_cache=None,
|
|
588
|
+
PyCache block_cache_compressed=None,
|
|
589
|
+
filter_policy=None,
|
|
590
|
+
no_block_cache=False,
|
|
591
|
+
block_size=None,
|
|
592
|
+
block_size_deviation=None,
|
|
593
|
+
block_restart_interval=None,
|
|
594
|
+
whole_key_filtering=None):
|
|
595
|
+
|
|
596
|
+
cdef table_factory.BlockBasedTableOptions table_options
|
|
597
|
+
|
|
598
|
+
if index_type == 'binary_search':
|
|
599
|
+
table_options.index_type = table_factory.kBinarySearch
|
|
600
|
+
elif index_type == 'hash_search':
|
|
601
|
+
table_options.index_type = table_factory.kHashSearch
|
|
602
|
+
else:
|
|
603
|
+
raise ValueError("Unknown index_type: %s" % index_type)
|
|
604
|
+
|
|
605
|
+
if hash_index_allow_collision:
|
|
606
|
+
table_options.hash_index_allow_collision = True
|
|
607
|
+
else:
|
|
608
|
+
table_options.hash_index_allow_collision = False
|
|
609
|
+
|
|
610
|
+
if checksum == 'crc32':
|
|
611
|
+
table_options.checksum = table_factory.kCRC32c
|
|
612
|
+
elif checksum == 'xxhash':
|
|
613
|
+
table_options.checksum = table_factory.kxxHash
|
|
614
|
+
else:
|
|
615
|
+
raise ValueError("Unknown checksum: %s" % checksum)
|
|
616
|
+
|
|
617
|
+
if no_block_cache:
|
|
618
|
+
table_options.no_block_cache = True
|
|
619
|
+
else:
|
|
620
|
+
table_options.no_block_cache = False
|
|
621
|
+
|
|
622
|
+
# If the following options are None use the rocksdb default.
|
|
623
|
+
if block_size is not None:
|
|
624
|
+
table_options.block_size = block_size
|
|
625
|
+
|
|
626
|
+
if block_size_deviation is not None:
|
|
627
|
+
table_options.block_size_deviation = block_size_deviation
|
|
628
|
+
|
|
629
|
+
if block_restart_interval is not None:
|
|
630
|
+
table_options.block_restart_interval = block_restart_interval
|
|
631
|
+
|
|
632
|
+
if whole_key_filtering is not None:
|
|
633
|
+
if whole_key_filtering:
|
|
634
|
+
table_options.whole_key_filtering = True
|
|
635
|
+
else:
|
|
636
|
+
table_options.whole_key_filtering = False
|
|
637
|
+
|
|
638
|
+
if block_cache is not None:
|
|
639
|
+
table_options.block_cache = block_cache.get_cache()
|
|
640
|
+
|
|
641
|
+
if block_cache_compressed is not None:
|
|
642
|
+
table_options.block_cache_compressed = block_cache_compressed.get_cache()
|
|
643
|
+
|
|
644
|
+
# Set the filter_policy
|
|
645
|
+
self.py_filter_policy = None
|
|
646
|
+
if filter_policy is not None:
|
|
647
|
+
if isinstance(filter_policy, PyFilterPolicy):
|
|
648
|
+
if (<PyFilterPolicy?>filter_policy).get_policy().get() == NULL:
|
|
649
|
+
raise Exception("Cannot set filter policy: %s" % filter_policy)
|
|
650
|
+
self.py_filter_policy = filter_policy
|
|
651
|
+
else:
|
|
652
|
+
self.py_filter_policy = PyGenericFilterPolicy(filter_policy)
|
|
653
|
+
|
|
654
|
+
table_options.filter_policy = self.py_filter_policy.get_policy()
|
|
655
|
+
|
|
656
|
+
self.factory.reset(table_factory.NewBlockBasedTableFactory(table_options))
|
|
657
|
+
|
|
658
|
+
cdef set_info_log(self, shared_ptr[logger.Logger] info_log):
|
|
659
|
+
if self.py_filter_policy is not None:
|
|
660
|
+
self.py_filter_policy.set_info_log(info_log)
|
|
661
|
+
|
|
662
|
+
|
|
663
|
+
cdef class PlainTableFactory(PyTableFactory):
|
|
664
|
+
def __init__(
|
|
665
|
+
self,
|
|
666
|
+
user_key_len=0,
|
|
667
|
+
bloom_bits_per_key=10,
|
|
668
|
+
hash_table_ratio=0.75,
|
|
669
|
+
index_sparseness=10,
|
|
670
|
+
huge_page_tlb_size=0,
|
|
671
|
+
encoding_type='plain',
|
|
672
|
+
py_bool full_scan_mode=False):
|
|
673
|
+
|
|
674
|
+
cdef table_factory.PlainTableOptions table_options
|
|
675
|
+
|
|
676
|
+
table_options.user_key_len = user_key_len
|
|
677
|
+
table_options.bloom_bits_per_key = bloom_bits_per_key
|
|
678
|
+
table_options.hash_table_ratio = hash_table_ratio
|
|
679
|
+
table_options.index_sparseness = index_sparseness
|
|
680
|
+
table_options.huge_page_tlb_size = huge_page_tlb_size
|
|
681
|
+
|
|
682
|
+
if encoding_type == 'plain':
|
|
683
|
+
table_options.encoding_type = table_factory.kPlain
|
|
684
|
+
elif encoding_type == 'prefix':
|
|
685
|
+
table_options.encoding_type = table_factory.kPrefix
|
|
686
|
+
else:
|
|
687
|
+
raise ValueError("Unknown encoding_type: %s" % encoding_type)
|
|
688
|
+
|
|
689
|
+
table_options.full_scan_mode = full_scan_mode
|
|
690
|
+
|
|
691
|
+
self.factory.reset( table_factory.NewPlainTableFactory(table_options))
|
|
692
|
+
#############################################
|
|
693
|
+
|
|
694
|
+
|
|
695
|
+
### Here are the MemtableFactories
|
|
696
|
+
cdef class PyMemtableFactory(object):
|
|
697
|
+
# pxd defines:
|
|
698
|
+
# cdef shared_ptr[memtablerep.MemTableRepFactory] factory
|
|
699
|
+
|
|
700
|
+
cdef shared_ptr[memtablerep.MemTableRepFactory] get_memtable_factory(self):
|
|
701
|
+
return self.factory
|
|
702
|
+
|
|
703
|
+
|
|
704
|
+
cdef class SkipListMemtableFactory(PyMemtableFactory):
|
|
705
|
+
def __init__(self):
|
|
706
|
+
self.factory.reset(memtablerep.NewSkipListFactory())
|
|
707
|
+
|
|
708
|
+
|
|
709
|
+
cdef class VectorMemtableFactory(PyMemtableFactory):
|
|
710
|
+
def __init__(self, count=0):
|
|
711
|
+
self.factory.reset(memtablerep.NewVectorRepFactory(count))
|
|
712
|
+
|
|
713
|
+
|
|
714
|
+
cdef class HashSkipListMemtableFactory(PyMemtableFactory):
|
|
715
|
+
def __init__(
|
|
716
|
+
self,
|
|
717
|
+
bucket_count=1000000,
|
|
718
|
+
skiplist_height=4,
|
|
719
|
+
skiplist_branching_factor=4):
|
|
720
|
+
|
|
721
|
+
self.factory.reset(
|
|
722
|
+
memtablerep.NewHashSkipListRepFactory(
|
|
723
|
+
bucket_count,
|
|
724
|
+
skiplist_height,
|
|
725
|
+
skiplist_branching_factor))
|
|
726
|
+
|
|
727
|
+
|
|
728
|
+
cdef class HashLinkListMemtableFactory(PyMemtableFactory):
|
|
729
|
+
def __init__(self, bucket_count=50000):
|
|
730
|
+
self.factory.reset(memtablerep.NewHashLinkListRepFactory(bucket_count))
|
|
731
|
+
##################################
|
|
732
|
+
|
|
733
|
+
|
|
734
|
+
cdef class CompressionType(object):
|
|
735
|
+
no_compression = u'no_compression'
|
|
736
|
+
snappy_compression = u'snappy_compression'
|
|
737
|
+
zlib_compression = u'zlib_compression'
|
|
738
|
+
bzip2_compression = u'bzip2_compression'
|
|
739
|
+
lz4_compression = u'lz4_compression'
|
|
740
|
+
lz4hc_compression = u'lz4hc_compression'
|
|
741
|
+
xpress_compression = u'xpress_compression'
|
|
742
|
+
zstd_compression = u'zstd_compression'
|
|
743
|
+
zstdnotfinal_compression = u'zstdnotfinal_compression'
|
|
744
|
+
disable_compression = u'disable_compression'
|
|
745
|
+
|
|
746
|
+
cdef class CompactionPri(object):
|
|
747
|
+
by_compensated_size = u'by_compensated_size'
|
|
748
|
+
oldest_largest_seq_first = u'oldest_largest_seq_first'
|
|
749
|
+
oldest_smallest_seq_first = u'oldest_smallest_seq_first'
|
|
750
|
+
min_overlapping_ratio = u'min_overlapping_ratio'
|
|
751
|
+
|
|
752
|
+
|
|
753
|
+
cdef class TxnDBWritePolicy(object):
|
|
754
|
+
write_committed = u'write_committed'
|
|
755
|
+
write_prepared = u'write_prepared'
|
|
756
|
+
write_unprepared = u'write_unprepared'
|
|
757
|
+
|
|
758
|
+
|
|
759
|
+
cdef class _ColumnFamilyHandle:
|
|
760
|
+
""" This is an internal class that we will weakref for safety """
|
|
761
|
+
# pxd defines:
|
|
762
|
+
# cdef db.ColumnFamilyHandle* handle
|
|
763
|
+
# cdef object __weakref__
|
|
764
|
+
# cdef object weak_handle
|
|
765
|
+
|
|
766
|
+
def __cinit__(self):
|
|
767
|
+
self.handle = NULL
|
|
768
|
+
|
|
769
|
+
def __dealloc__(self):
|
|
770
|
+
if not self.handle == NULL:
|
|
771
|
+
del self.handle
|
|
772
|
+
|
|
773
|
+
@staticmethod
|
|
774
|
+
cdef from_handle_ptr(db.ColumnFamilyHandle* handle):
|
|
775
|
+
inst = <_ColumnFamilyHandle>_ColumnFamilyHandle.__new__(_ColumnFamilyHandle)
|
|
776
|
+
inst.handle = handle
|
|
777
|
+
return inst
|
|
778
|
+
|
|
779
|
+
@property
|
|
780
|
+
def name(self):
|
|
781
|
+
return self.handle.GetName()
|
|
782
|
+
|
|
783
|
+
@property
|
|
784
|
+
def id(self):
|
|
785
|
+
return self.handle.GetID()
|
|
786
|
+
|
|
787
|
+
@property
|
|
788
|
+
def weakref(self):
|
|
789
|
+
if self.weak_handle is None:
|
|
790
|
+
self.weak_handle = ColumnFamilyHandle.from_wrapper(self)
|
|
791
|
+
return self.weak_handle
|
|
792
|
+
|
|
793
|
+
cdef class ColumnFamilyHandle:
|
|
794
|
+
""" This represents a ColumnFamilyHandle """
|
|
795
|
+
# cdef object _ref
|
|
796
|
+
# cdef readonly bytes name
|
|
797
|
+
# cdef readonly int id
|
|
798
|
+
|
|
799
|
+
def __cinit__(self, weakhandle):
|
|
800
|
+
self._ref = weakhandle
|
|
801
|
+
self.name = self._ref().name
|
|
802
|
+
self.id = self._ref().id
|
|
803
|
+
|
|
804
|
+
def __init__(self, *):
|
|
805
|
+
raise TypeError("These can not be constructed from Python")
|
|
806
|
+
|
|
807
|
+
@staticmethod
|
|
808
|
+
cdef object from_wrapper(_ColumnFamilyHandle real_handle):
|
|
809
|
+
return ColumnFamilyHandle.__new__(ColumnFamilyHandle, weakref.ref(real_handle))
|
|
810
|
+
|
|
811
|
+
@property
|
|
812
|
+
def is_valid(self):
|
|
813
|
+
return self._ref() is not None
|
|
814
|
+
|
|
815
|
+
def __repr__(self):
|
|
816
|
+
valid = "valid" if self.is_valid else "invalid"
|
|
817
|
+
return f"<ColumnFamilyHandle name: {self.name}, id: {self.id}, state: {valid}>"
|
|
818
|
+
|
|
819
|
+
cdef db.ColumnFamilyHandle* get_handle(self) except NULL:
|
|
820
|
+
cdef _ColumnFamilyHandle real_handle = self._ref()
|
|
821
|
+
if real_handle is None:
|
|
822
|
+
raise ValueError(f"{self} is no longer a valid ColumnFamilyHandle!")
|
|
823
|
+
return real_handle.handle
|
|
824
|
+
|
|
825
|
+
def __eq__(self, other):
|
|
826
|
+
cdef ColumnFamilyHandle fast_other
|
|
827
|
+
if isinstance(other, ColumnFamilyHandle):
|
|
828
|
+
fast_other = other
|
|
829
|
+
return (
|
|
830
|
+
self.name == fast_other.name
|
|
831
|
+
and self.id == fast_other.id
|
|
832
|
+
and self._ref == fast_other._ref
|
|
833
|
+
)
|
|
834
|
+
return False
|
|
835
|
+
|
|
836
|
+
def __lt__(self, other):
|
|
837
|
+
cdef ColumnFamilyHandle fast_other
|
|
838
|
+
if isinstance(other, ColumnFamilyHandle):
|
|
839
|
+
return self.id < other.id
|
|
840
|
+
return NotImplemented
|
|
841
|
+
|
|
842
|
+
# Since @total_ordering isn't a thing for cython
|
|
843
|
+
def __ne__(self, other):
|
|
844
|
+
return not self == other
|
|
845
|
+
|
|
846
|
+
def __gt__(self, other):
|
|
847
|
+
return other < self
|
|
848
|
+
|
|
849
|
+
def __le__(self, other):
|
|
850
|
+
return not other < self
|
|
851
|
+
|
|
852
|
+
def __ge__(self, other):
|
|
853
|
+
return not self < other
|
|
854
|
+
|
|
855
|
+
def __hash__(self):
|
|
856
|
+
# hash of a weakref matches that of its original ref'ed object
|
|
857
|
+
# so we use the id of our weakref object here to prevent
|
|
858
|
+
# a situation where we are invalid, but match a valid handle's hash
|
|
859
|
+
return hash((self.id, self.name, id(self._ref)))
|
|
860
|
+
|
|
861
|
+
|
|
862
|
+
cdef class ColumnFamilyOptions(object):
|
|
863
|
+
# pxd defines:
|
|
864
|
+
# cdef options.ColumnFamilyOptions* copts
|
|
865
|
+
# cdef PyComparator py_comparator
|
|
866
|
+
# cdef PyMergeOperator py_merge_operator
|
|
867
|
+
# cdef PySliceTransform py_prefix_extractor
|
|
868
|
+
# cdef PyTableFactory py_table_factory
|
|
869
|
+
# cdef PyMemtableFactory py_memtable_factory
|
|
870
|
+
# cdef cpp_bool in_use
|
|
871
|
+
|
|
872
|
+
def __cinit__(self):
|
|
873
|
+
self.copts = NULL
|
|
874
|
+
self.copts = new options.ColumnFamilyOptions()
|
|
875
|
+
self.in_use = False
|
|
876
|
+
|
|
877
|
+
def __dealloc__(self):
|
|
878
|
+
if not self.copts == NULL:
|
|
879
|
+
del self.copts
|
|
880
|
+
|
|
881
|
+
def __init__(self, **kwargs):
|
|
882
|
+
self.py_comparator = BytewiseComparator()
|
|
883
|
+
self.py_merge_operator = None
|
|
884
|
+
self.py_prefix_extractor = None
|
|
885
|
+
self.py_table_factory = None
|
|
886
|
+
self.py_memtable_factory = None
|
|
887
|
+
|
|
888
|
+
for key, value in kwargs.items():
|
|
889
|
+
setattr(self, key, value)
|
|
890
|
+
|
|
891
|
+
property write_buffer_size:
|
|
892
|
+
def __get__(self):
|
|
893
|
+
return self.copts.write_buffer_size
|
|
894
|
+
def __set__(self, value):
|
|
895
|
+
self.copts.write_buffer_size = value
|
|
896
|
+
|
|
897
|
+
property max_write_buffer_number:
|
|
898
|
+
def __get__(self):
|
|
899
|
+
return self.copts.max_write_buffer_number
|
|
900
|
+
def __set__(self, value):
|
|
901
|
+
self.copts.max_write_buffer_number = value
|
|
902
|
+
|
|
903
|
+
property min_write_buffer_number_to_merge:
|
|
904
|
+
def __get__(self):
|
|
905
|
+
return self.copts.min_write_buffer_number_to_merge
|
|
906
|
+
def __set__(self, value):
|
|
907
|
+
self.copts.min_write_buffer_number_to_merge = value
|
|
908
|
+
|
|
909
|
+
property compression_opts:
|
|
910
|
+
def __get__(self):
|
|
911
|
+
cdef dict ret_ob = {}
|
|
912
|
+
|
|
913
|
+
ret_ob['window_bits'] = self.copts.compression_opts.window_bits
|
|
914
|
+
ret_ob['level'] = self.copts.compression_opts.level
|
|
915
|
+
ret_ob['strategy'] = self.copts.compression_opts.strategy
|
|
916
|
+
ret_ob['max_dict_bytes'] = self.copts.compression_opts.max_dict_bytes
|
|
917
|
+
|
|
918
|
+
return ret_ob
|
|
919
|
+
|
|
920
|
+
def __set__(self, dict value):
|
|
921
|
+
cdef options.CompressionOptions* copts
|
|
922
|
+
copts = cython.address(self.copts.compression_opts)
|
|
923
|
+
# CompressionOptions(int wbits, int _lev, int _strategy, int _max_dict_bytes)
|
|
924
|
+
if 'window_bits' in value:
|
|
925
|
+
copts.window_bits = value['window_bits']
|
|
926
|
+
if 'level' in value:
|
|
927
|
+
copts.level = value['level']
|
|
928
|
+
if 'strategy' in value:
|
|
929
|
+
copts.strategy = value['strategy']
|
|
930
|
+
if 'max_dict_bytes' in value:
|
|
931
|
+
copts.max_dict_bytes = value['max_dict_bytes']
|
|
932
|
+
|
|
933
|
+
property compaction_pri:
|
|
934
|
+
def __get__(self):
|
|
935
|
+
if self.copts.compaction_pri == options.kByCompensatedSize:
|
|
936
|
+
return CompactionPri.by_compensated_size
|
|
937
|
+
if self.copts.compaction_pri == options.kOldestLargestSeqFirst:
|
|
938
|
+
return CompactionPri.oldest_largest_seq_first
|
|
939
|
+
if self.copts.compaction_pri == options.kOldestSmallestSeqFirst:
|
|
940
|
+
return CompactionPri.oldest_smallest_seq_first
|
|
941
|
+
if self.copts.compaction_pri == options.kMinOverlappingRatio:
|
|
942
|
+
return CompactionPri.min_overlapping_ratio
|
|
943
|
+
def __set__(self, value):
|
|
944
|
+
if value == CompactionPri.by_compensated_size:
|
|
945
|
+
self.copts.compaction_pri = options.kByCompensatedSize
|
|
946
|
+
elif value == CompactionPri.oldest_largest_seq_first:
|
|
947
|
+
self.copts.compaction_pri = options.kOldestLargestSeqFirst
|
|
948
|
+
elif value == CompactionPri.oldest_smallest_seq_first:
|
|
949
|
+
self.copts.compaction_pri = options.kOldestSmallestSeqFirst
|
|
950
|
+
elif value == CompactionPri.min_overlapping_ratio:
|
|
951
|
+
self.copts.compaction_pri = options.kMinOverlappingRatio
|
|
952
|
+
else:
|
|
953
|
+
raise TypeError("Unknown compaction pri: %s" % value)
|
|
954
|
+
|
|
955
|
+
property compression:
|
|
956
|
+
def __get__(self):
|
|
957
|
+
if self.copts.compression == options.kNoCompression:
|
|
958
|
+
return CompressionType.no_compression
|
|
959
|
+
elif self.copts.compression == options.kSnappyCompression:
|
|
960
|
+
return CompressionType.snappy_compression
|
|
961
|
+
elif self.copts.compression == options.kZlibCompression:
|
|
962
|
+
return CompressionType.zlib_compression
|
|
963
|
+
elif self.copts.compression == options.kBZip2Compression:
|
|
964
|
+
return CompressionType.bzip2_compression
|
|
965
|
+
elif self.copts.compression == options.kLZ4Compression:
|
|
966
|
+
return CompressionType.lz4_compression
|
|
967
|
+
elif self.copts.compression == options.kLZ4HCCompression:
|
|
968
|
+
return CompressionType.lz4hc_compression
|
|
969
|
+
elif self.copts.compression == options.kXpressCompression:
|
|
970
|
+
return CompressionType.xpress_compression
|
|
971
|
+
elif self.copts.compression == options.kZSTD:
|
|
972
|
+
return CompressionType.zstd_compression
|
|
973
|
+
elif self.copts.compression == options.kZSTDNotFinalCompression:
|
|
974
|
+
return CompressionType.zstdnotfinal_compression
|
|
975
|
+
elif self.copts.compression == options.kDisableCompressionOption:
|
|
976
|
+
return CompressionType.disable_compression
|
|
977
|
+
else:
|
|
978
|
+
raise Exception("Unknonw type: %s" % self.opts.compression)
|
|
979
|
+
|
|
980
|
+
def __set__(self, value):
|
|
981
|
+
if value == CompressionType.no_compression:
|
|
982
|
+
self.copts.compression = options.kNoCompression
|
|
983
|
+
elif value == CompressionType.snappy_compression:
|
|
984
|
+
self.copts.compression = options.kSnappyCompression
|
|
985
|
+
elif value == CompressionType.zlib_compression:
|
|
986
|
+
self.copts.compression = options.kZlibCompression
|
|
987
|
+
elif value == CompressionType.bzip2_compression:
|
|
988
|
+
self.copts.compression = options.kBZip2Compression
|
|
989
|
+
elif value == CompressionType.lz4_compression:
|
|
990
|
+
self.copts.compression = options.kLZ4Compression
|
|
991
|
+
elif value == CompressionType.lz4hc_compression:
|
|
992
|
+
self.copts.compression = options.kLZ4HCCompression
|
|
993
|
+
elif value == CompressionType.zstd_compression:
|
|
994
|
+
self.copts.compression = options.kZSTD
|
|
995
|
+
elif value == CompressionType.zstdnotfinal_compression:
|
|
996
|
+
self.copts.compression = options.kZSTDNotFinalCompression
|
|
997
|
+
elif value == CompressionType.disable_compression:
|
|
998
|
+
self.copts.compression = options.kDisableCompressionOption
|
|
999
|
+
else:
|
|
1000
|
+
raise TypeError("Unknown compression: %s" % value)
|
|
1001
|
+
|
|
1002
|
+
property max_compaction_bytes:
|
|
1003
|
+
def __get__(self):
|
|
1004
|
+
return self.copts.max_compaction_bytes
|
|
1005
|
+
def __set__(self, value):
|
|
1006
|
+
self.copts.max_compaction_bytes = value
|
|
1007
|
+
|
|
1008
|
+
property num_levels:
|
|
1009
|
+
def __get__(self):
|
|
1010
|
+
return self.copts.num_levels
|
|
1011
|
+
def __set__(self, value):
|
|
1012
|
+
self.copts.num_levels = value
|
|
1013
|
+
|
|
1014
|
+
property level0_file_num_compaction_trigger:
|
|
1015
|
+
def __get__(self):
|
|
1016
|
+
return self.copts.level0_file_num_compaction_trigger
|
|
1017
|
+
def __set__(self, value):
|
|
1018
|
+
self.copts.level0_file_num_compaction_trigger = value
|
|
1019
|
+
|
|
1020
|
+
property level0_slowdown_writes_trigger:
|
|
1021
|
+
def __get__(self):
|
|
1022
|
+
return self.copts.level0_slowdown_writes_trigger
|
|
1023
|
+
def __set__(self, value):
|
|
1024
|
+
self.copts.level0_slowdown_writes_trigger = value
|
|
1025
|
+
|
|
1026
|
+
property level0_stop_writes_trigger:
|
|
1027
|
+
def __get__(self):
|
|
1028
|
+
return self.copts.level0_stop_writes_trigger
|
|
1029
|
+
def __set__(self, value):
|
|
1030
|
+
self.copts.level0_stop_writes_trigger = value
|
|
1031
|
+
|
|
1032
|
+
property max_mem_compaction_level:
|
|
1033
|
+
def __get__(self):
|
|
1034
|
+
return self.copts.max_mem_compaction_level
|
|
1035
|
+
def __set__(self, value):
|
|
1036
|
+
self.copts.max_mem_compaction_level = value
|
|
1037
|
+
|
|
1038
|
+
property target_file_size_base:
|
|
1039
|
+
def __get__(self):
|
|
1040
|
+
return self.copts.target_file_size_base
|
|
1041
|
+
def __set__(self, value):
|
|
1042
|
+
self.copts.target_file_size_base = value
|
|
1043
|
+
|
|
1044
|
+
property target_file_size_multiplier:
|
|
1045
|
+
def __get__(self):
|
|
1046
|
+
return self.copts.target_file_size_multiplier
|
|
1047
|
+
def __set__(self, value):
|
|
1048
|
+
self.copts.target_file_size_multiplier = value
|
|
1049
|
+
|
|
1050
|
+
property max_bytes_for_level_base:
|
|
1051
|
+
def __get__(self):
|
|
1052
|
+
return self.copts.max_bytes_for_level_base
|
|
1053
|
+
def __set__(self, value):
|
|
1054
|
+
self.copts.max_bytes_for_level_base = value
|
|
1055
|
+
|
|
1056
|
+
property max_bytes_for_level_multiplier:
|
|
1057
|
+
def __get__(self):
|
|
1058
|
+
return self.copts.max_bytes_for_level_multiplier
|
|
1059
|
+
def __set__(self, value):
|
|
1060
|
+
self.copts.max_bytes_for_level_multiplier = value
|
|
1061
|
+
|
|
1062
|
+
property max_bytes_for_level_multiplier_additional:
|
|
1063
|
+
def __get__(self):
|
|
1064
|
+
return self.copts.max_bytes_for_level_multiplier_additional
|
|
1065
|
+
def __set__(self, value):
|
|
1066
|
+
self.copts.max_bytes_for_level_multiplier_additional = value
|
|
1067
|
+
|
|
1068
|
+
property arena_block_size:
|
|
1069
|
+
def __get__(self):
|
|
1070
|
+
return self.copts.arena_block_size
|
|
1071
|
+
def __set__(self, value):
|
|
1072
|
+
self.copts.arena_block_size = value
|
|
1073
|
+
|
|
1074
|
+
property disable_auto_compactions:
|
|
1075
|
+
def __get__(self):
|
|
1076
|
+
return self.copts.disable_auto_compactions
|
|
1077
|
+
def __set__(self, value):
|
|
1078
|
+
self.copts.disable_auto_compactions = value
|
|
1079
|
+
|
|
1080
|
+
# FIXME: remove to util/options_helper.h
|
|
1081
|
+
# property allow_os_buffer:
|
|
1082
|
+
# def __get__(self):
|
|
1083
|
+
# return self.copts.allow_os_buffer
|
|
1084
|
+
# def __set__(self, value):
|
|
1085
|
+
# self.copts.allow_os_buffer = value
|
|
1086
|
+
|
|
1087
|
+
property compaction_style:
|
|
1088
|
+
def __get__(self):
|
|
1089
|
+
if self.copts.compaction_style == kCompactionStyleLevel:
|
|
1090
|
+
return 'level'
|
|
1091
|
+
if self.copts.compaction_style == kCompactionStyleUniversal:
|
|
1092
|
+
return 'universal'
|
|
1093
|
+
if self.copts.compaction_style == kCompactionStyleFIFO:
|
|
1094
|
+
return 'fifo'
|
|
1095
|
+
if self.copts.compaction_style == kCompactionStyleNone:
|
|
1096
|
+
return 'none'
|
|
1097
|
+
raise Exception("Unknown compaction_style")
|
|
1098
|
+
|
|
1099
|
+
def __set__(self, str value):
|
|
1100
|
+
if value == 'level':
|
|
1101
|
+
self.copts.compaction_style = kCompactionStyleLevel
|
|
1102
|
+
elif value == 'universal':
|
|
1103
|
+
self.copts.compaction_style = kCompactionStyleUniversal
|
|
1104
|
+
elif value == 'fifo':
|
|
1105
|
+
self.copts.compaction_style = kCompactionStyleFIFO
|
|
1106
|
+
elif value == 'none':
|
|
1107
|
+
self.copts.compaction_style = kCompactionStyleNone
|
|
1108
|
+
else:
|
|
1109
|
+
raise Exception("Unknown compaction style")
|
|
1110
|
+
|
|
1111
|
+
property compaction_options_universal:
|
|
1112
|
+
def __get__(self):
|
|
1113
|
+
cdef universal_compaction.CompactionOptionsUniversal uopts
|
|
1114
|
+
cdef dict ret_ob = {}
|
|
1115
|
+
|
|
1116
|
+
uopts = self.copts.compaction_options_universal
|
|
1117
|
+
|
|
1118
|
+
ret_ob['size_ratio'] = uopts.size_ratio
|
|
1119
|
+
ret_ob['min_merge_width'] = uopts.min_merge_width
|
|
1120
|
+
ret_ob['max_merge_width'] = uopts.max_merge_width
|
|
1121
|
+
ret_ob['max_size_amplification_percent'] = uopts.max_size_amplification_percent
|
|
1122
|
+
ret_ob['compression_size_percent'] = uopts.compression_size_percent
|
|
1123
|
+
|
|
1124
|
+
if uopts.stop_style == kCompactionStopStyleSimilarSize:
|
|
1125
|
+
ret_ob['stop_style'] = 'similar_size'
|
|
1126
|
+
elif uopts.stop_style == kCompactionStopStyleTotalSize:
|
|
1127
|
+
ret_ob['stop_style'] = 'total_size'
|
|
1128
|
+
else:
|
|
1129
|
+
raise Exception("Unknown compaction style")
|
|
1130
|
+
|
|
1131
|
+
return ret_ob
|
|
1132
|
+
|
|
1133
|
+
def __set__(self, dict value):
|
|
1134
|
+
cdef universal_compaction.CompactionOptionsUniversal* uopts
|
|
1135
|
+
uopts = cython.address(self.copts.compaction_options_universal)
|
|
1136
|
+
|
|
1137
|
+
if 'size_ratio' in value:
|
|
1138
|
+
uopts.size_ratio = value['size_ratio']
|
|
1139
|
+
|
|
1140
|
+
if 'min_merge_width' in value:
|
|
1141
|
+
uopts.min_merge_width = value['min_merge_width']
|
|
1142
|
+
|
|
1143
|
+
if 'max_merge_width' in value:
|
|
1144
|
+
uopts.max_merge_width = value['max_merge_width']
|
|
1145
|
+
|
|
1146
|
+
if 'max_size_amplification_percent' in value:
|
|
1147
|
+
uopts.max_size_amplification_percent = value['max_size_amplification_percent']
|
|
1148
|
+
|
|
1149
|
+
if 'compression_size_percent' in value:
|
|
1150
|
+
uopts.compression_size_percent = value['compression_size_percent']
|
|
1151
|
+
|
|
1152
|
+
if 'stop_style' in value:
|
|
1153
|
+
if value['stop_style'] == 'similar_size':
|
|
1154
|
+
uopts.stop_style = kCompactionStopStyleSimilarSize
|
|
1155
|
+
elif value['stop_style'] == 'total_size':
|
|
1156
|
+
uopts.stop_style = kCompactionStopStyleTotalSize
|
|
1157
|
+
else:
|
|
1158
|
+
raise Exception("Unknown compaction style")
|
|
1159
|
+
|
|
1160
|
+
# Deprecate
|
|
1161
|
+
# property filter_deletes:
|
|
1162
|
+
# def __get__(self):
|
|
1163
|
+
# return self.copts.filter_deletes
|
|
1164
|
+
# def __set__(self, value):
|
|
1165
|
+
# self.copts.filter_deletes = value
|
|
1166
|
+
|
|
1167
|
+
property max_sequential_skip_in_iterations:
|
|
1168
|
+
def __get__(self):
|
|
1169
|
+
return self.copts.max_sequential_skip_in_iterations
|
|
1170
|
+
def __set__(self, value):
|
|
1171
|
+
self.copts.max_sequential_skip_in_iterations = value
|
|
1172
|
+
|
|
1173
|
+
property inplace_update_support:
|
|
1174
|
+
def __get__(self):
|
|
1175
|
+
return self.copts.inplace_update_support
|
|
1176
|
+
def __set__(self, value):
|
|
1177
|
+
self.copts.inplace_update_support = value
|
|
1178
|
+
|
|
1179
|
+
property table_factory:
|
|
1180
|
+
def __get__(self):
|
|
1181
|
+
return self.py_table_factory
|
|
1182
|
+
|
|
1183
|
+
def __set__(self, PyTableFactory value):
|
|
1184
|
+
self.py_table_factory = value
|
|
1185
|
+
self.copts.table_factory = value.get_table_factory()
|
|
1186
|
+
|
|
1187
|
+
property memtable_factory:
|
|
1188
|
+
def __get__(self):
|
|
1189
|
+
return self.py_memtable_factory
|
|
1190
|
+
|
|
1191
|
+
def __set__(self, PyMemtableFactory value):
|
|
1192
|
+
self.py_memtable_factory = value
|
|
1193
|
+
self.copts.memtable_factory = value.get_memtable_factory()
|
|
1194
|
+
|
|
1195
|
+
property inplace_update_num_locks:
|
|
1196
|
+
def __get__(self):
|
|
1197
|
+
return self.copts.inplace_update_num_locks
|
|
1198
|
+
def __set__(self, value):
|
|
1199
|
+
self.copts.inplace_update_num_locks = value
|
|
1200
|
+
|
|
1201
|
+
property comparator:
|
|
1202
|
+
def __get__(self):
|
|
1203
|
+
return self.py_comparator.get_ob()
|
|
1204
|
+
|
|
1205
|
+
def __set__(self, value):
|
|
1206
|
+
if isinstance(value, PyComparator):
|
|
1207
|
+
if (<PyComparator?>value).get_comparator() == NULL:
|
|
1208
|
+
raise Exception("Cannot set %s as comparator" % value)
|
|
1209
|
+
else:
|
|
1210
|
+
self.py_comparator = value
|
|
1211
|
+
else:
|
|
1212
|
+
self.py_comparator = PyGenericComparator(value)
|
|
1213
|
+
|
|
1214
|
+
self.copts.comparator = self.py_comparator.get_comparator()
|
|
1215
|
+
|
|
1216
|
+
property merge_operator:
|
|
1217
|
+
def __get__(self):
|
|
1218
|
+
if self.py_merge_operator is None:
|
|
1219
|
+
return None
|
|
1220
|
+
return self.py_merge_operator.get_ob()
|
|
1221
|
+
|
|
1222
|
+
def __set__(self, value):
|
|
1223
|
+
self.py_merge_operator = PyMergeOperator(value)
|
|
1224
|
+
self.copts.merge_operator = self.py_merge_operator.get_operator()
|
|
1225
|
+
|
|
1226
|
+
property prefix_extractor:
|
|
1227
|
+
def __get__(self):
|
|
1228
|
+
if self.py_prefix_extractor is None:
|
|
1229
|
+
return None
|
|
1230
|
+
return self.py_prefix_extractor.get_ob()
|
|
1231
|
+
|
|
1232
|
+
def __set__(self, value):
|
|
1233
|
+
self.py_prefix_extractor = PySliceTransform(value)
|
|
1234
|
+
self.copts.prefix_extractor = self.py_prefix_extractor.get_transformer()
|
|
1235
|
+
|
|
1236
|
+
|
|
1237
|
+
cdef class Options(ColumnFamilyOptions):
|
|
1238
|
+
# pxd defines:
|
|
1239
|
+
# cdef options.Options* opts
|
|
1240
|
+
# cdef PyCache py_row_cache
|
|
1241
|
+
|
|
1242
|
+
def __cinit__(self):
|
|
1243
|
+
# Destroy the existing ColumnFamilyOptions()
|
|
1244
|
+
del self.copts
|
|
1245
|
+
self.opts = NULL
|
|
1246
|
+
self.copts = self.opts = new options.Options()
|
|
1247
|
+
self.in_use = False
|
|
1248
|
+
|
|
1249
|
+
def __dealloc__(self):
|
|
1250
|
+
if not self.opts == NULL:
|
|
1251
|
+
self.copts = NULL
|
|
1252
|
+
del self.opts
|
|
1253
|
+
|
|
1254
|
+
def __init__(self, **kwargs):
|
|
1255
|
+
ColumnFamilyOptions.__init__(self)
|
|
1256
|
+
self.py_row_cache = None
|
|
1257
|
+
|
|
1258
|
+
for key, value in kwargs.items():
|
|
1259
|
+
setattr(self, key, value)
|
|
1260
|
+
|
|
1261
|
+
property create_if_missing:
|
|
1262
|
+
def __get__(self):
|
|
1263
|
+
return self.opts.create_if_missing
|
|
1264
|
+
def __set__(self, value):
|
|
1265
|
+
self.opts.create_if_missing = value
|
|
1266
|
+
|
|
1267
|
+
property error_if_exists:
|
|
1268
|
+
def __get__(self):
|
|
1269
|
+
return self.opts.error_if_exists
|
|
1270
|
+
def __set__(self, value):
|
|
1271
|
+
self.opts.error_if_exists = value
|
|
1272
|
+
|
|
1273
|
+
property paranoid_checks:
|
|
1274
|
+
def __get__(self):
|
|
1275
|
+
return self.opts.paranoid_checks
|
|
1276
|
+
def __set__(self, value):
|
|
1277
|
+
self.opts.paranoid_checks = value
|
|
1278
|
+
|
|
1279
|
+
property max_open_files:
|
|
1280
|
+
def __get__(self):
|
|
1281
|
+
return self.opts.max_open_files
|
|
1282
|
+
def __set__(self, value):
|
|
1283
|
+
self.opts.max_open_files = value
|
|
1284
|
+
|
|
1285
|
+
property use_fsync:
|
|
1286
|
+
def __get__(self):
|
|
1287
|
+
return self.opts.use_fsync
|
|
1288
|
+
def __set__(self, value):
|
|
1289
|
+
self.opts.use_fsync = value
|
|
1290
|
+
|
|
1291
|
+
property db_log_dir:
|
|
1292
|
+
def __get__(self):
|
|
1293
|
+
return string_to_path(self.opts.db_log_dir)
|
|
1294
|
+
def __set__(self, value):
|
|
1295
|
+
self.opts.db_log_dir = path_to_string(value)
|
|
1296
|
+
|
|
1297
|
+
property wal_dir:
|
|
1298
|
+
def __get__(self):
|
|
1299
|
+
return string_to_path(self.opts.wal_dir)
|
|
1300
|
+
def __set__(self, value):
|
|
1301
|
+
self.opts.wal_dir = path_to_string(value)
|
|
1302
|
+
|
|
1303
|
+
property delete_obsolete_files_period_micros:
|
|
1304
|
+
def __get__(self):
|
|
1305
|
+
return self.opts.delete_obsolete_files_period_micros
|
|
1306
|
+
def __set__(self, value):
|
|
1307
|
+
self.opts.delete_obsolete_files_period_micros = value
|
|
1308
|
+
|
|
1309
|
+
property max_background_compactions:
|
|
1310
|
+
def __get__(self):
|
|
1311
|
+
return self.opts.max_background_compactions
|
|
1312
|
+
def __set__(self, value):
|
|
1313
|
+
self.opts.max_background_compactions = value
|
|
1314
|
+
|
|
1315
|
+
property max_background_flushes:
|
|
1316
|
+
def __get__(self):
|
|
1317
|
+
return self.opts.max_background_flushes
|
|
1318
|
+
def __set__(self, value):
|
|
1319
|
+
self.opts.max_background_flushes = value
|
|
1320
|
+
|
|
1321
|
+
property max_log_file_size:
|
|
1322
|
+
def __get__(self):
|
|
1323
|
+
return self.opts.max_log_file_size
|
|
1324
|
+
def __set__(self, value):
|
|
1325
|
+
self.opts.max_log_file_size = value
|
|
1326
|
+
|
|
1327
|
+
property db_write_buffer_size:
|
|
1328
|
+
def __get__(self):
|
|
1329
|
+
return self.opts.db_write_buffer_size
|
|
1330
|
+
def __set__(self, value):
|
|
1331
|
+
self.opts.db_write_buffer_size = value
|
|
1332
|
+
|
|
1333
|
+
property log_file_time_to_roll:
|
|
1334
|
+
def __get__(self):
|
|
1335
|
+
return self.opts.log_file_time_to_roll
|
|
1336
|
+
def __set__(self, value):
|
|
1337
|
+
self.opts.log_file_time_to_roll = value
|
|
1338
|
+
|
|
1339
|
+
property keep_log_file_num:
|
|
1340
|
+
def __get__(self):
|
|
1341
|
+
return self.opts.keep_log_file_num
|
|
1342
|
+
def __set__(self, value):
|
|
1343
|
+
self.opts.keep_log_file_num = value
|
|
1344
|
+
|
|
1345
|
+
property max_manifest_file_size:
|
|
1346
|
+
def __get__(self):
|
|
1347
|
+
return self.opts.max_manifest_file_size
|
|
1348
|
+
def __set__(self, value):
|
|
1349
|
+
self.opts.max_manifest_file_size = value
|
|
1350
|
+
|
|
1351
|
+
property table_cache_numshardbits:
|
|
1352
|
+
def __get__(self):
|
|
1353
|
+
return self.opts.table_cache_numshardbits
|
|
1354
|
+
def __set__(self, value):
|
|
1355
|
+
self.opts.table_cache_numshardbits = value
|
|
1356
|
+
|
|
1357
|
+
property wal_ttl_seconds:
|
|
1358
|
+
def __get__(self):
|
|
1359
|
+
return self.opts.WAL_ttl_seconds
|
|
1360
|
+
def __set__(self, value):
|
|
1361
|
+
self.opts.WAL_ttl_seconds = value
|
|
1362
|
+
|
|
1363
|
+
property wal_size_limit_mb:
|
|
1364
|
+
def __get__(self):
|
|
1365
|
+
return self.opts.WAL_size_limit_MB
|
|
1366
|
+
def __set__(self, value):
|
|
1367
|
+
self.opts.WAL_size_limit_MB = value
|
|
1368
|
+
|
|
1369
|
+
property manifest_preallocation_size:
|
|
1370
|
+
def __get__(self):
|
|
1371
|
+
return self.opts.manifest_preallocation_size
|
|
1372
|
+
def __set__(self, value):
|
|
1373
|
+
self.opts.manifest_preallocation_size = value
|
|
1374
|
+
|
|
1375
|
+
property enable_write_thread_adaptive_yield:
|
|
1376
|
+
def __get__(self):
|
|
1377
|
+
return self.opts.enable_write_thread_adaptive_yield
|
|
1378
|
+
def __set__(self, value):
|
|
1379
|
+
self.opts.enable_write_thread_adaptive_yield = value
|
|
1380
|
+
|
|
1381
|
+
property allow_concurrent_memtable_write:
|
|
1382
|
+
def __get__(self):
|
|
1383
|
+
return self.opts.allow_concurrent_memtable_write
|
|
1384
|
+
def __set__(self, value):
|
|
1385
|
+
self.opts.allow_concurrent_memtable_write = value
|
|
1386
|
+
|
|
1387
|
+
property allow_mmap_reads:
|
|
1388
|
+
def __get__(self):
|
|
1389
|
+
return self.opts.allow_mmap_reads
|
|
1390
|
+
def __set__(self, value):
|
|
1391
|
+
self.opts.allow_mmap_reads = value
|
|
1392
|
+
|
|
1393
|
+
property allow_mmap_writes:
|
|
1394
|
+
def __get__(self):
|
|
1395
|
+
return self.opts.allow_mmap_writes
|
|
1396
|
+
def __set__(self, value):
|
|
1397
|
+
self.opts.allow_mmap_writes = value
|
|
1398
|
+
|
|
1399
|
+
property is_fd_close_on_exec:
|
|
1400
|
+
def __get__(self):
|
|
1401
|
+
return self.opts.is_fd_close_on_exec
|
|
1402
|
+
def __set__(self, value):
|
|
1403
|
+
self.opts.is_fd_close_on_exec = value
|
|
1404
|
+
|
|
1405
|
+
property stats_dump_period_sec:
|
|
1406
|
+
def __get__(self):
|
|
1407
|
+
return self.opts.stats_dump_period_sec
|
|
1408
|
+
def __set__(self, value):
|
|
1409
|
+
self.opts.stats_dump_period_sec = value
|
|
1410
|
+
|
|
1411
|
+
property advise_random_on_open:
|
|
1412
|
+
def __get__(self):
|
|
1413
|
+
return self.opts.advise_random_on_open
|
|
1414
|
+
def __set__(self, value):
|
|
1415
|
+
self.opts.advise_random_on_open = value
|
|
1416
|
+
|
|
1417
|
+
# TODO: need to remove -Wconversion to make this work
|
|
1418
|
+
# property access_hint_on_compaction_start:
|
|
1419
|
+
# def __get__(self):
|
|
1420
|
+
# return self.opts.access_hint_on_compaction_start
|
|
1421
|
+
# def __set__(self, AccessHint value):
|
|
1422
|
+
# self.opts.access_hint_on_compaction_start = value
|
|
1423
|
+
|
|
1424
|
+
property use_adaptive_mutex:
|
|
1425
|
+
def __get__(self):
|
|
1426
|
+
return self.opts.use_adaptive_mutex
|
|
1427
|
+
def __set__(self, value):
|
|
1428
|
+
self.opts.use_adaptive_mutex = value
|
|
1429
|
+
|
|
1430
|
+
property bytes_per_sync:
|
|
1431
|
+
def __get__(self):
|
|
1432
|
+
return self.opts.bytes_per_sync
|
|
1433
|
+
def __set__(self, value):
|
|
1434
|
+
self.opts.bytes_per_sync = value
|
|
1435
|
+
|
|
1436
|
+
property row_cache:
|
|
1437
|
+
def __get__(self):
|
|
1438
|
+
return self.py_row_cache
|
|
1439
|
+
|
|
1440
|
+
def __set__(self, value):
|
|
1441
|
+
if value is None:
|
|
1442
|
+
self.py_row_cache = None
|
|
1443
|
+
self.opts.row_cache.reset()
|
|
1444
|
+
elif not isinstance(value, PyCache):
|
|
1445
|
+
raise Exception("row_cache must be a Cache object")
|
|
1446
|
+
else:
|
|
1447
|
+
self.py_row_cache = value
|
|
1448
|
+
self.opts.row_cache = self.py_row_cache.get_cache()
|
|
1449
|
+
|
|
1450
|
+
|
|
1451
|
+
# cpp_bool skip_checking_sst_file_sizes_on_db_open
|
|
1452
|
+
property skip_checking_sst_file_sizes_on_db_open:
|
|
1453
|
+
def __get__(self):
|
|
1454
|
+
return self.opts.skip_checking_sst_file_sizes_on_db_open
|
|
1455
|
+
def __set__(self, value):
|
|
1456
|
+
self.opts.skip_checking_sst_file_sizes_on_db_open = value
|
|
1457
|
+
|
|
1458
|
+
# cpp_bool skip_stats_update_on_db_open
|
|
1459
|
+
property skip_stats_update_on_db_open:
|
|
1460
|
+
def __get__(self):
|
|
1461
|
+
return self.opts.skip_stats_update_on_db_open
|
|
1462
|
+
def __set__(self, value):
|
|
1463
|
+
self.opts.skip_stats_update_on_db_open = value
|
|
1464
|
+
|
|
1465
|
+
|
|
1466
|
+
cdef class TransactionDBOptions(object):
|
|
1467
|
+
# pxd defines:
|
|
1468
|
+
# cdef transaction.TransactionDBOptions* opts
|
|
1469
|
+
# cdef bint in_use
|
|
1470
|
+
|
|
1471
|
+
def __cinit__(self):
|
|
1472
|
+
self.opts = new transaction.TransactionDBOptions()
|
|
1473
|
+
self.in_use = False
|
|
1474
|
+
|
|
1475
|
+
def __dealloc__(self):
|
|
1476
|
+
if self.opts != NULL:
|
|
1477
|
+
del self.opts
|
|
1478
|
+
self.opts = NULL
|
|
1479
|
+
|
|
1480
|
+
def __init__(self, **kwargs):
|
|
1481
|
+
for key, value in kwargs.items():
|
|
1482
|
+
setattr(self, key, value)
|
|
1483
|
+
|
|
1484
|
+
property max_num_locks:
|
|
1485
|
+
def __get__(self):
|
|
1486
|
+
return self.opts.max_num_locks
|
|
1487
|
+
def __set__(self, value):
|
|
1488
|
+
self.opts.max_num_locks = value
|
|
1489
|
+
|
|
1490
|
+
property max_num_deadlocks:
|
|
1491
|
+
def __get__(self):
|
|
1492
|
+
return self.opts.max_num_deadlocks
|
|
1493
|
+
def __set__(self, value):
|
|
1494
|
+
self.opts.max_num_deadlocks = value
|
|
1495
|
+
|
|
1496
|
+
property num_stripes:
|
|
1497
|
+
def __get__(self):
|
|
1498
|
+
return self.opts.num_stripes
|
|
1499
|
+
def __set__(self, value):
|
|
1500
|
+
self.opts.num_stripes = value
|
|
1501
|
+
|
|
1502
|
+
property transaction_lock_timeout:
|
|
1503
|
+
def __get__(self):
|
|
1504
|
+
return self.opts.transaction_lock_timeout
|
|
1505
|
+
def __set__(self, value):
|
|
1506
|
+
self.opts.transaction_lock_timeout = value
|
|
1507
|
+
|
|
1508
|
+
property default_lock_timeout:
|
|
1509
|
+
def __get__(self):
|
|
1510
|
+
return self.opts.default_lock_timeout
|
|
1511
|
+
def __set__(self, value):
|
|
1512
|
+
self.opts.default_lock_timeout = value
|
|
1513
|
+
|
|
1514
|
+
property write_policy:
|
|
1515
|
+
def __get__(self):
|
|
1516
|
+
if self.opts.write_policy == transaction.WRITE_COMMITTED:
|
|
1517
|
+
return TxnDBWritePolicy.write_committed
|
|
1518
|
+
elif self.opts.write_policy == transaction.WRITE_PREPARED:
|
|
1519
|
+
return TxnDBWritePolicy.write_prepared
|
|
1520
|
+
elif self.opts.write_policy == transaction.WRITE_UNPREPARED:
|
|
1521
|
+
return TxnDBWritePolicy.write_unprepared
|
|
1522
|
+
raise TypeError("Unknown write policy value: %r" % self.opts.write_policy)
|
|
1523
|
+
|
|
1524
|
+
def __set__(self, value):
|
|
1525
|
+
if value in (TxnDBWritePolicy.write_committed, b'write_committed', 'write_committed'):
|
|
1526
|
+
self.opts.write_policy = transaction.WRITE_COMMITTED
|
|
1527
|
+
elif value in (TxnDBWritePolicy.write_prepared, b'write_prepared', 'write_prepared'):
|
|
1528
|
+
self.opts.write_policy = transaction.WRITE_PREPARED
|
|
1529
|
+
elif value in (TxnDBWritePolicy.write_unprepared, b'write_unprepared', 'write_unprepared'):
|
|
1530
|
+
self.opts.write_policy = transaction.WRITE_UNPREPARED
|
|
1531
|
+
else:
|
|
1532
|
+
raise TypeError("Unknown transaction write policy: %r" % value)
|
|
1533
|
+
|
|
1534
|
+
property rollback_merge_operands:
|
|
1535
|
+
def __get__(self):
|
|
1536
|
+
return self.opts.rollback_merge_operands
|
|
1537
|
+
def __set__(self, value):
|
|
1538
|
+
self.opts.rollback_merge_operands = value
|
|
1539
|
+
|
|
1540
|
+
property skip_concurrency_control:
|
|
1541
|
+
def __get__(self):
|
|
1542
|
+
return self.opts.skip_concurrency_control
|
|
1543
|
+
def __set__(self, value):
|
|
1544
|
+
self.opts.skip_concurrency_control = value
|
|
1545
|
+
|
|
1546
|
+
property default_write_batch_flush_threshold:
|
|
1547
|
+
def __get__(self):
|
|
1548
|
+
return self.opts.default_write_batch_flush_threshold
|
|
1549
|
+
def __set__(self, value):
|
|
1550
|
+
self.opts.default_write_batch_flush_threshold = value
|
|
1551
|
+
|
|
1552
|
+
|
|
1553
|
+
cdef class TransactionOptions(object):
|
|
1554
|
+
# pxd defines:
|
|
1555
|
+
# cdef transaction.TransactionOptions* opts
|
|
1556
|
+
|
|
1557
|
+
def __cinit__(self):
|
|
1558
|
+
self.opts = new transaction.TransactionOptions()
|
|
1559
|
+
|
|
1560
|
+
def __dealloc__(self):
|
|
1561
|
+
if self.opts != NULL:
|
|
1562
|
+
del self.opts
|
|
1563
|
+
self.opts = NULL
|
|
1564
|
+
|
|
1565
|
+
def __init__(self, **kwargs):
|
|
1566
|
+
for key, value in kwargs.items():
|
|
1567
|
+
setattr(self, key, value)
|
|
1568
|
+
|
|
1569
|
+
property set_snapshot:
|
|
1570
|
+
def __get__(self):
|
|
1571
|
+
return self.opts.set_snapshot
|
|
1572
|
+
def __set__(self, value):
|
|
1573
|
+
self.opts.set_snapshot = value
|
|
1574
|
+
|
|
1575
|
+
property deadlock_detect:
|
|
1576
|
+
def __get__(self):
|
|
1577
|
+
return self.opts.deadlock_detect
|
|
1578
|
+
def __set__(self, value):
|
|
1579
|
+
self.opts.deadlock_detect = value
|
|
1580
|
+
|
|
1581
|
+
property use_only_the_last_commit_time_batch_for_recovery:
|
|
1582
|
+
def __get__(self):
|
|
1583
|
+
return self.opts.use_only_the_last_commit_time_batch_for_recovery
|
|
1584
|
+
def __set__(self, value):
|
|
1585
|
+
self.opts.use_only_the_last_commit_time_batch_for_recovery = value
|
|
1586
|
+
|
|
1587
|
+
property lock_timeout:
|
|
1588
|
+
def __get__(self):
|
|
1589
|
+
return self.opts.lock_timeout
|
|
1590
|
+
def __set__(self, value):
|
|
1591
|
+
self.opts.lock_timeout = value
|
|
1592
|
+
|
|
1593
|
+
property expiration:
|
|
1594
|
+
def __get__(self):
|
|
1595
|
+
return self.opts.expiration
|
|
1596
|
+
def __set__(self, value):
|
|
1597
|
+
self.opts.expiration = value
|
|
1598
|
+
|
|
1599
|
+
property deadlock_detect_depth:
|
|
1600
|
+
def __get__(self):
|
|
1601
|
+
return self.opts.deadlock_detect_depth
|
|
1602
|
+
def __set__(self, value):
|
|
1603
|
+
self.opts.deadlock_detect_depth = value
|
|
1604
|
+
|
|
1605
|
+
property max_write_batch_size:
|
|
1606
|
+
def __get__(self):
|
|
1607
|
+
return self.opts.max_write_batch_size
|
|
1608
|
+
def __set__(self, value):
|
|
1609
|
+
self.opts.max_write_batch_size = value
|
|
1610
|
+
|
|
1611
|
+
property skip_concurrency_control:
|
|
1612
|
+
def __get__(self):
|
|
1613
|
+
return self.opts.skip_concurrency_control
|
|
1614
|
+
def __set__(self, value):
|
|
1615
|
+
self.opts.skip_concurrency_control = value
|
|
1616
|
+
|
|
1617
|
+
property skip_prepare:
|
|
1618
|
+
def __get__(self):
|
|
1619
|
+
return self.opts.skip_prepare
|
|
1620
|
+
def __set__(self, value):
|
|
1621
|
+
self.opts.skip_prepare = value
|
|
1622
|
+
|
|
1623
|
+
property write_batch_flush_threshold:
|
|
1624
|
+
def __get__(self):
|
|
1625
|
+
return self.opts.write_batch_flush_threshold
|
|
1626
|
+
def __set__(self, value):
|
|
1627
|
+
self.opts.write_batch_flush_threshold = value
|
|
1628
|
+
|
|
1629
|
+
|
|
1630
|
+
|
|
1631
|
+
# TODO inherit from writableDB
|
|
1632
|
+
cdef class WriteBatch(object):
|
|
1633
|
+
# pxd defines:
|
|
1634
|
+
# cdef db.WriteBatch* batch
|
|
1635
|
+
|
|
1636
|
+
def __cinit__(self, data=None):
|
|
1637
|
+
self.batch = NULL
|
|
1638
|
+
if data is not None:
|
|
1639
|
+
self.batch = new db.WriteBatch(bytes_to_string(data))
|
|
1640
|
+
else:
|
|
1641
|
+
self.batch = new db.WriteBatch()
|
|
1642
|
+
|
|
1643
|
+
def __dealloc__(self):
|
|
1644
|
+
if not self.batch == NULL:
|
|
1645
|
+
del self.batch
|
|
1646
|
+
|
|
1647
|
+
cpdef void put(self, bytes key, bytes value, ColumnFamilyHandle column_family = None):
|
|
1648
|
+
cdef db.ColumnFamilyHandle* cf_handle = NULL
|
|
1649
|
+
if column_family is not None:
|
|
1650
|
+
cf_handle = column_family.get_handle()
|
|
1651
|
+
# nullptr is default family
|
|
1652
|
+
self.batch.Put(cf_handle, bytes_to_slice(key), bytes_to_slice(value))
|
|
1653
|
+
|
|
1654
|
+
cpdef void merge(self, bytes key, bytes value, ColumnFamilyHandle column_family = None):
|
|
1655
|
+
cdef db.ColumnFamilyHandle* cf_handle = NULL
|
|
1656
|
+
if column_family is not None:
|
|
1657
|
+
cf_handle = column_family.get_handle()
|
|
1658
|
+
# nullptr is default family
|
|
1659
|
+
self.batch.Merge(cf_handle, bytes_to_slice(key), bytes_to_slice(value))
|
|
1660
|
+
|
|
1661
|
+
# Here delete is with def for backwards compatibility.
|
|
1662
|
+
# Cython has a bug that doesn't allow a method with name `delete`
|
|
1663
|
+
# so we have to use a different name for `cpdef`-ed ones.
|
|
1664
|
+
def delete(self, bytes key, ColumnFamilyHandle column_family = None):
|
|
1665
|
+
return self.delete_single(key, column_family)
|
|
1666
|
+
|
|
1667
|
+
cpdef void delete_single(self, bytes key, ColumnFamilyHandle column_family = None):
|
|
1668
|
+
cdef db.ColumnFamilyHandle* cf_handle = NULL
|
|
1669
|
+
if column_family is not None:
|
|
1670
|
+
cf_handle = column_family.get_handle()
|
|
1671
|
+
# nullptr is default family
|
|
1672
|
+
self.batch.Delete(cf_handle, bytes_to_slice(key))
|
|
1673
|
+
|
|
1674
|
+
cpdef void delete_range(self, bytes begin_key, bytes end_key, ColumnFamilyHandle column_family = None):
|
|
1675
|
+
cdef db.ColumnFamilyHandle* cf_handle = NULL
|
|
1676
|
+
if column_family is not None:
|
|
1677
|
+
cf_handle = column_family.get_handle()
|
|
1678
|
+
|
|
1679
|
+
# nullptr is default family
|
|
1680
|
+
self.batch.DeleteRange(cf_handle, bytes_to_slice(begin_key), bytes_to_slice(end_key))
|
|
1681
|
+
|
|
1682
|
+
cpdef void clear(self):
|
|
1683
|
+
self.batch.Clear()
|
|
1684
|
+
|
|
1685
|
+
cpdef data(self):
|
|
1686
|
+
return string_to_bytes(self.batch.Data())
|
|
1687
|
+
|
|
1688
|
+
cpdef int count(self):
|
|
1689
|
+
return self.batch.Count()
|
|
1690
|
+
|
|
1691
|
+
def __iter__(self):
|
|
1692
|
+
return WriteBatchIterator(self)
|
|
1693
|
+
|
|
1694
|
+
|
|
1695
|
+
cdef class WriteBatchIterator(object):
|
|
1696
|
+
# Need a reference to the WriteBatch.
|
|
1697
|
+
# The BatchItems are only pointers to the memory in WriteBatch.
|
|
1698
|
+
|
|
1699
|
+
# pxd defines:
|
|
1700
|
+
# cdef WriteBatch batch
|
|
1701
|
+
# cdef vector[db.BatchItem] items
|
|
1702
|
+
# cdef size_t pos
|
|
1703
|
+
|
|
1704
|
+
def __init__(self, WriteBatch batch):
|
|
1705
|
+
cdef Status st
|
|
1706
|
+
|
|
1707
|
+
self.batch = batch
|
|
1708
|
+
self.pos = 0
|
|
1709
|
+
|
|
1710
|
+
st = db.get_batch_items(batch.batch, cython.address(self.items))
|
|
1711
|
+
check_status(st)
|
|
1712
|
+
|
|
1713
|
+
def __iter__(self):
|
|
1714
|
+
return self
|
|
1715
|
+
|
|
1716
|
+
def __next__(self):
|
|
1717
|
+
if self.pos == self.items.size():
|
|
1718
|
+
raise StopIteration()
|
|
1719
|
+
|
|
1720
|
+
cdef str op
|
|
1721
|
+
|
|
1722
|
+
if self.items[self.pos].op == db.BatchItemOpPut:
|
|
1723
|
+
op = "Put"
|
|
1724
|
+
elif self.items[self.pos].op == db.BatchItemOpMerge:
|
|
1725
|
+
op = "Merge"
|
|
1726
|
+
elif self.items[self.pos].op == db.BatchItemOpDelte:
|
|
1727
|
+
op = "Delete"
|
|
1728
|
+
|
|
1729
|
+
if self.items[self.pos].column_family_id != 0: # Column Family is set
|
|
1730
|
+
ret = (
|
|
1731
|
+
op,
|
|
1732
|
+
(
|
|
1733
|
+
self.items[self.pos].column_family_id,
|
|
1734
|
+
slice_to_bytes(self.items[self.pos].key)
|
|
1735
|
+
),
|
|
1736
|
+
slice_to_bytes(self.items[self.pos].value)
|
|
1737
|
+
)
|
|
1738
|
+
else:
|
|
1739
|
+
ret = (
|
|
1740
|
+
op,
|
|
1741
|
+
slice_to_bytes(self.items[self.pos].key),
|
|
1742
|
+
slice_to_bytes(self.items[self.pos].value)
|
|
1743
|
+
)
|
|
1744
|
+
self.pos += 1
|
|
1745
|
+
return ret
|
|
1746
|
+
|
|
1747
|
+
|
|
1748
|
+
# TODO add writableDB, ReadablewritableDB
|
|
1749
|
+
# TODO add WriteBatch iniherited from writableDB
|
|
1750
|
+
|
|
1751
|
+
|
|
1752
|
+
cdef class IDB(object):
|
|
1753
|
+
# Cython requires to implement methods in the class definition
|
|
1754
|
+
# even for abstract classes.
|
|
1755
|
+
|
|
1756
|
+
# TODO move write option arguments to a separate class
|
|
1757
|
+
cpdef void put(self, bytes key, bytes value, cpp_bool sync = False, cpp_bool disable_wal = False, ColumnFamilyHandle column_family = None):
|
|
1758
|
+
pass
|
|
1759
|
+
cpdef void delete_single(self, bytes key, cpp_bool sync = False, cpp_bool disable_wal = False, ColumnFamilyHandle column_family = None):
|
|
1760
|
+
pass
|
|
1761
|
+
cpdef void delete_range(self, bytes begin_key, bytes end_key, cpp_bool sync = False, cpp_bool disable_wal = False, ColumnFamilyHandle column_family = None):
|
|
1762
|
+
pass
|
|
1763
|
+
cpdef void flush(self):
|
|
1764
|
+
pass
|
|
1765
|
+
cpdef void flush_wal(self, cpp_bool sync = False):
|
|
1766
|
+
pass
|
|
1767
|
+
cpdef void merge(self, bytes key, bytes value, cpp_bool sync = False, cpp_bool disable_wal = False, ColumnFamilyHandle column_family = None):
|
|
1768
|
+
pass
|
|
1769
|
+
cpdef void write(self, WriteBatch batch, cpp_bool sync = False, cpp_bool disable_wal = False):
|
|
1770
|
+
pass
|
|
1771
|
+
cpdef get(self, bytes key, ColumnFamilyHandle column_family = None):
|
|
1772
|
+
pass
|
|
1773
|
+
cpdef multi_get(self, keys):
|
|
1774
|
+
pass
|
|
1775
|
+
cpdef key_may_exist(self, bytes key, cpp_bool fetch = False, ColumnFamilyHandle column_family = None):
|
|
1776
|
+
pass
|
|
1777
|
+
cpdef Iterator iterkeys(self, ColumnFamilyHandle column_family = None):
|
|
1778
|
+
pass
|
|
1779
|
+
cpdef Iterator itervalues(self, ColumnFamilyHandle column_family = None):
|
|
1780
|
+
pass
|
|
1781
|
+
cpdef Iterator iteritems(self, ColumnFamilyHandle column_family = None):
|
|
1782
|
+
pass
|
|
1783
|
+
|
|
1784
|
+
|
|
1785
|
+
@cython.no_gc_clear
|
|
1786
|
+
cdef class DB(IDB):
|
|
1787
|
+
# pxd defines:
|
|
1788
|
+
# cdef Options opts
|
|
1789
|
+
# cdef db.DB* db
|
|
1790
|
+
# cdef list cf_handles
|
|
1791
|
+
# cdef list cf_options
|
|
1792
|
+
|
|
1793
|
+
def __cinit__(
|
|
1794
|
+
self,
|
|
1795
|
+
db_name,
|
|
1796
|
+
Options opts,
|
|
1797
|
+
dict column_families=None,
|
|
1798
|
+
read_only=False,
|
|
1799
|
+
secondary_path=None,
|
|
1800
|
+
txn_db_opts=None,
|
|
1801
|
+
):
|
|
1802
|
+
cdef Status st
|
|
1803
|
+
cdef string db_path
|
|
1804
|
+
cdef string secondary_path_c
|
|
1805
|
+
cdef vector[db.ColumnFamilyDescriptor] column_family_descriptors
|
|
1806
|
+
cdef vector[db.ColumnFamilyHandle*] column_family_handles
|
|
1807
|
+
cdef bytes default_cf_name = db.kDefaultColumnFamilyName
|
|
1808
|
+
self.db = NULL
|
|
1809
|
+
self.opts = None
|
|
1810
|
+
self.cf_handles = []
|
|
1811
|
+
self.cf_options = []
|
|
1812
|
+
|
|
1813
|
+
# TransactionDB subclasses handle opening the underlying C++ handle
|
|
1814
|
+
# themselves. Skipping here prevents double initialisation that leads to
|
|
1815
|
+
# use-after-free during teardown.
|
|
1816
|
+
if isinstance(self, TransactionDB):
|
|
1817
|
+
return
|
|
1818
|
+
|
|
1819
|
+
# TransactionDB passes txn_db_opts so it can manage opening the C++
|
|
1820
|
+
# TransactionDB itself. When present we skip the vanilla DB open here
|
|
1821
|
+
# and let the subclass finish initialisation.
|
|
1822
|
+
if txn_db_opts is not None:
|
|
1823
|
+
return
|
|
1824
|
+
|
|
1825
|
+
if opts.in_use:
|
|
1826
|
+
raise Exception("Options object is already used by another DB")
|
|
1827
|
+
|
|
1828
|
+
db_path = path_to_string(db_name)
|
|
1829
|
+
if not column_families or default_cf_name not in column_families:
|
|
1830
|
+
# Always add the default column family
|
|
1831
|
+
column_family_descriptors.push_back(
|
|
1832
|
+
db.ColumnFamilyDescriptor(
|
|
1833
|
+
db.kDefaultColumnFamilyName,
|
|
1834
|
+
options.ColumnFamilyOptions(deref(opts.opts))
|
|
1835
|
+
)
|
|
1836
|
+
)
|
|
1837
|
+
self.cf_options.append(None) # Since they are the same as db
|
|
1838
|
+
if column_families:
|
|
1839
|
+
for cf_name, cf_options in column_families.items():
|
|
1840
|
+
if not isinstance(cf_name, bytes):
|
|
1841
|
+
raise TypeError(
|
|
1842
|
+
f"column family name {cf_name!r} is not of type {bytes}!"
|
|
1843
|
+
)
|
|
1844
|
+
if not isinstance(cf_options, ColumnFamilyOptions):
|
|
1845
|
+
raise TypeError(
|
|
1846
|
+
f"column family options {cf_options!r} is not of type "
|
|
1847
|
+
f"{ColumnFamilyOptions}!"
|
|
1848
|
+
)
|
|
1849
|
+
if (<ColumnFamilyOptions>cf_options).in_use:
|
|
1850
|
+
raise Exception(
|
|
1851
|
+
f"ColumnFamilyOptions object for {cf_name} is already "
|
|
1852
|
+
"used by another Column Family"
|
|
1853
|
+
)
|
|
1854
|
+
(<ColumnFamilyOptions>cf_options).in_use = True
|
|
1855
|
+
column_family_descriptors.push_back(
|
|
1856
|
+
db.ColumnFamilyDescriptor(
|
|
1857
|
+
cf_name,
|
|
1858
|
+
deref((<ColumnFamilyOptions>cf_options).copts)
|
|
1859
|
+
)
|
|
1860
|
+
)
|
|
1861
|
+
self.cf_options.append(cf_options)
|
|
1862
|
+
|
|
1863
|
+
if secondary_path is not None:
|
|
1864
|
+
assert read_only
|
|
1865
|
+
secondary_path_c = path_to_string(secondary_path)
|
|
1866
|
+
with nogil:
|
|
1867
|
+
st = db.DB_OpenAsSecondary_ColumnFamilies(
|
|
1868
|
+
deref(opts.opts),
|
|
1869
|
+
db_path,
|
|
1870
|
+
secondary_path_c,
|
|
1871
|
+
column_family_descriptors,
|
|
1872
|
+
&column_family_handles,
|
|
1873
|
+
&self.db)
|
|
1874
|
+
elif read_only:
|
|
1875
|
+
with nogil:
|
|
1876
|
+
st = db.DB_OpenForReadOnly_ColumnFamilies(
|
|
1877
|
+
deref(opts.opts),
|
|
1878
|
+
db_path,
|
|
1879
|
+
column_family_descriptors,
|
|
1880
|
+
&column_family_handles,
|
|
1881
|
+
&self.db,
|
|
1882
|
+
False)
|
|
1883
|
+
else:
|
|
1884
|
+
with nogil:
|
|
1885
|
+
st = db.DB_Open_ColumnFamilies(
|
|
1886
|
+
deref(opts.opts),
|
|
1887
|
+
db_path,
|
|
1888
|
+
column_family_descriptors,
|
|
1889
|
+
&column_family_handles,
|
|
1890
|
+
&self.db)
|
|
1891
|
+
check_status(st)
|
|
1892
|
+
|
|
1893
|
+
for handle in column_family_handles:
|
|
1894
|
+
wrapper = _ColumnFamilyHandle.from_handle_ptr(handle)
|
|
1895
|
+
self.cf_handles.append(wrapper)
|
|
1896
|
+
|
|
1897
|
+
# Inject the loggers into the python callbacks
|
|
1898
|
+
cdef shared_ptr[logger.Logger] info_log = self.db.GetOptions(
|
|
1899
|
+
self.db.DefaultColumnFamily()).info_log
|
|
1900
|
+
if opts.py_comparator is not None:
|
|
1901
|
+
opts.py_comparator.set_info_log(info_log)
|
|
1902
|
+
|
|
1903
|
+
if opts.py_table_factory is not None:
|
|
1904
|
+
opts.py_table_factory.set_info_log(info_log)
|
|
1905
|
+
|
|
1906
|
+
if opts.prefix_extractor is not None:
|
|
1907
|
+
opts.py_prefix_extractor.set_info_log(info_log)
|
|
1908
|
+
|
|
1909
|
+
cdef ColumnFamilyOptions copts
|
|
1910
|
+
for idx, copts in enumerate(self.cf_options):
|
|
1911
|
+
if not copts:
|
|
1912
|
+
continue
|
|
1913
|
+
|
|
1914
|
+
info_log = self.db.GetOptions(column_family_handles[idx]).info_log
|
|
1915
|
+
|
|
1916
|
+
if copts.py_comparator is not None:
|
|
1917
|
+
copts.py_comparator.set_info_log(info_log)
|
|
1918
|
+
|
|
1919
|
+
if copts.py_table_factory is not None:
|
|
1920
|
+
copts.py_table_factory.set_info_log(info_log)
|
|
1921
|
+
|
|
1922
|
+
if copts.prefix_extractor is not None:
|
|
1923
|
+
copts.py_prefix_extractor.set_info_log(info_log)
|
|
1924
|
+
|
|
1925
|
+
self.opts = opts
|
|
1926
|
+
self.opts.in_use = True
|
|
1927
|
+
|
|
1928
|
+
def __dealloc__(self):
|
|
1929
|
+
self.close()
|
|
1930
|
+
|
|
1931
|
+
cpdef void close(self):
|
|
1932
|
+
cdef ColumnFamilyOptions copts
|
|
1933
|
+
if self.db != NULL:
|
|
1934
|
+
# We have to make sure we delete the handles so rocksdb doesn't
|
|
1935
|
+
# assert when we delete the db
|
|
1936
|
+
self.cf_handles.clear()
|
|
1937
|
+
for copts in self.cf_options:
|
|
1938
|
+
if copts:
|
|
1939
|
+
copts.in_use = False
|
|
1940
|
+
self.cf_options.clear()
|
|
1941
|
+
|
|
1942
|
+
with nogil:
|
|
1943
|
+
del self.db
|
|
1944
|
+
|
|
1945
|
+
if self.opts is not None:
|
|
1946
|
+
self.opts.in_use = False
|
|
1947
|
+
|
|
1948
|
+
@property
|
|
1949
|
+
def column_families(self):
|
|
1950
|
+
return [handle.weakref for handle in self.cf_handles]
|
|
1951
|
+
|
|
1952
|
+
cpdef get_column_family(self, bytes name):
|
|
1953
|
+
for handle in self.cf_handles:
|
|
1954
|
+
if handle.name == name:
|
|
1955
|
+
return handle.weakref
|
|
1956
|
+
|
|
1957
|
+
cpdef void put(self, bytes key, bytes value, cpp_bool sync = False, cpp_bool disable_wal = False, ColumnFamilyHandle column_family = None):
|
|
1958
|
+
cdef Status st
|
|
1959
|
+
cdef options.WriteOptions opts
|
|
1960
|
+
opts.sync = sync
|
|
1961
|
+
opts.disableWAL = disable_wal
|
|
1962
|
+
|
|
1963
|
+
cdef Slice c_key = bytes_to_slice(key)
|
|
1964
|
+
cdef Slice c_value = bytes_to_slice(value)
|
|
1965
|
+
cdef db.ColumnFamilyHandle* cf_handle = self.db.DefaultColumnFamily()
|
|
1966
|
+
|
|
1967
|
+
if column_family is not None:
|
|
1968
|
+
cf_handle = column_family.get_handle()
|
|
1969
|
+
|
|
1970
|
+
with nogil:
|
|
1971
|
+
st = self.db.Put(opts, cf_handle, c_key, c_value)
|
|
1972
|
+
check_status(st)
|
|
1973
|
+
|
|
1974
|
+
def delete(self, bytes key, cpp_bool sync = False, cpp_bool disable_wal = False, ColumnFamilyHandle column_family = None):
|
|
1975
|
+
self.delete_single(key, sync=sync, disable_wal=disable_wal, column_family=column_family)
|
|
1976
|
+
|
|
1977
|
+
cpdef void delete_single(self, bytes key, cpp_bool sync = False, cpp_bool disable_wal = False, ColumnFamilyHandle column_family = None):
|
|
1978
|
+
cdef Status st
|
|
1979
|
+
cdef options.WriteOptions opts
|
|
1980
|
+
opts.sync = sync
|
|
1981
|
+
opts.disableWAL = disable_wal
|
|
1982
|
+
|
|
1983
|
+
cdef Slice c_key = bytes_to_slice(key)
|
|
1984
|
+
cdef db.ColumnFamilyHandle* cf_handle = self.db.DefaultColumnFamily()
|
|
1985
|
+
|
|
1986
|
+
if column_family is not None:
|
|
1987
|
+
cf_handle = column_family.get_handle()
|
|
1988
|
+
|
|
1989
|
+
with nogil:
|
|
1990
|
+
st = self.db.Delete(opts, cf_handle, c_key)
|
|
1991
|
+
check_status(st)
|
|
1992
|
+
|
|
1993
|
+
cpdef void delete_range(self, bytes begin_key, bytes end_key, cpp_bool sync = False, cpp_bool disable_wal = False, ColumnFamilyHandle column_family = None):
|
|
1994
|
+
cdef Status st
|
|
1995
|
+
cdef options.WriteOptions opts
|
|
1996
|
+
opts.sync = sync
|
|
1997
|
+
opts.disableWAL = disable_wal
|
|
1998
|
+
|
|
1999
|
+
cdef Slice c_begin_key = bytes_to_slice(begin_key)
|
|
2000
|
+
cdef Slice c_end_key = bytes_to_slice(end_key)
|
|
2001
|
+
|
|
2002
|
+
cdef db.ColumnFamilyHandle* cf_handle = self.db.DefaultColumnFamily()
|
|
2003
|
+
if column_family is not None:
|
|
2004
|
+
cf_handle = column_family.get_handle()
|
|
2005
|
+
|
|
2006
|
+
with nogil:
|
|
2007
|
+
st = self.db.DeleteRange(opts, cf_handle, c_begin_key, c_end_key)
|
|
2008
|
+
check_status(st)
|
|
2009
|
+
|
|
2010
|
+
cpdef void flush(self):
|
|
2011
|
+
cdef Status st
|
|
2012
|
+
cdef FlushOptions options
|
|
2013
|
+
cdef db.ColumnFamilyHandle* cf_handle = self.db.DefaultColumnFamily()
|
|
2014
|
+
|
|
2015
|
+
with nogil:
|
|
2016
|
+
st = self.db.Flush(options, cf_handle)
|
|
2017
|
+
check_status(st)
|
|
2018
|
+
|
|
2019
|
+
cpdef void flush_wal(self, cpp_bool sync = False):
|
|
2020
|
+
cdef Status st
|
|
2021
|
+
cdef cpp_bool c_sync = sync
|
|
2022
|
+
with nogil:
|
|
2023
|
+
st = self.db.FlushWAL(c_sync)
|
|
2024
|
+
check_status(st)
|
|
2025
|
+
|
|
2026
|
+
cpdef void merge(self, bytes key, bytes value, cpp_bool sync = False, cpp_bool disable_wal = False, ColumnFamilyHandle column_family = None):
|
|
2027
|
+
cdef Status st
|
|
2028
|
+
cdef options.WriteOptions opts
|
|
2029
|
+
opts.sync = sync
|
|
2030
|
+
opts.disableWAL = disable_wal
|
|
2031
|
+
|
|
2032
|
+
cdef Slice c_key = bytes_to_slice(key)
|
|
2033
|
+
cdef Slice c_value = bytes_to_slice(value)
|
|
2034
|
+
cdef db.ColumnFamilyHandle* cf_handle = self.db.DefaultColumnFamily()
|
|
2035
|
+
if column_family is not None:
|
|
2036
|
+
cf_handle = column_family.get_handle()
|
|
2037
|
+
|
|
2038
|
+
with nogil:
|
|
2039
|
+
st = self.db.Merge(opts, cf_handle, c_key, c_value)
|
|
2040
|
+
check_status(st)
|
|
2041
|
+
|
|
2042
|
+
cpdef void write(self, WriteBatch batch, cpp_bool sync = False, cpp_bool disable_wal = False):
|
|
2043
|
+
cdef Status st
|
|
2044
|
+
cdef options.WriteOptions opts
|
|
2045
|
+
opts.sync = sync
|
|
2046
|
+
opts.disableWAL = disable_wal
|
|
2047
|
+
|
|
2048
|
+
with nogil:
|
|
2049
|
+
st = self.db.Write(opts, batch.batch)
|
|
2050
|
+
check_status(st)
|
|
2051
|
+
|
|
2052
|
+
cpdef get(self, bytes key, ColumnFamilyHandle column_family = None):
|
|
2053
|
+
cdef string res
|
|
2054
|
+
cdef Status st
|
|
2055
|
+
cdef options.ReadOptions opts
|
|
2056
|
+
|
|
2057
|
+
cdef Slice c_key = bytes_to_slice(key)
|
|
2058
|
+
cdef db.ColumnFamilyHandle* cf_handle = self.db.DefaultColumnFamily()
|
|
2059
|
+
if column_family is not None:
|
|
2060
|
+
cf_handle = column_family.get_handle()
|
|
2061
|
+
|
|
2062
|
+
with nogil:
|
|
2063
|
+
st = self.db.Get(opts, cf_handle, c_key, cython.address(res))
|
|
2064
|
+
|
|
2065
|
+
if st.ok():
|
|
2066
|
+
return string_to_bytes(res)
|
|
2067
|
+
elif st.IsNotFound():
|
|
2068
|
+
return None
|
|
2069
|
+
else:
|
|
2070
|
+
check_status(st)
|
|
2071
|
+
|
|
2072
|
+
cpdef multi_get(self, keys):
|
|
2073
|
+
cdef vector[string] values
|
|
2074
|
+
values.resize(len(keys))
|
|
2075
|
+
|
|
2076
|
+
cdef db.ColumnFamilyHandle* cf_handle
|
|
2077
|
+
cdef vector[db.ColumnFamilyHandle*] cf_handles
|
|
2078
|
+
cdef vector[Slice] c_keys
|
|
2079
|
+
for key in keys:
|
|
2080
|
+
if isinstance(key, tuple):
|
|
2081
|
+
py_handle, key = key
|
|
2082
|
+
cf_handle = (<ColumnFamilyHandle?>py_handle).get_handle()
|
|
2083
|
+
else:
|
|
2084
|
+
cf_handle = self.db.DefaultColumnFamily()
|
|
2085
|
+
c_keys.push_back(bytes_to_slice(key))
|
|
2086
|
+
cf_handles.push_back(cf_handle)
|
|
2087
|
+
|
|
2088
|
+
cdef options.ReadOptions opts
|
|
2089
|
+
|
|
2090
|
+
cdef vector[Status] res
|
|
2091
|
+
with nogil:
|
|
2092
|
+
res = self.db.MultiGet(
|
|
2093
|
+
opts,
|
|
2094
|
+
cf_handles,
|
|
2095
|
+
c_keys,
|
|
2096
|
+
cython.address(values))
|
|
2097
|
+
|
|
2098
|
+
cdef dict ret_dict = {}
|
|
2099
|
+
for index in range(len(keys)):
|
|
2100
|
+
if res[index].ok():
|
|
2101
|
+
ret_dict[keys[index]] = string_to_bytes(values[index])
|
|
2102
|
+
elif res[index].IsNotFound():
|
|
2103
|
+
ret_dict[keys[index]] = None
|
|
2104
|
+
else:
|
|
2105
|
+
check_status(res[index])
|
|
2106
|
+
|
|
2107
|
+
return ret_dict
|
|
2108
|
+
|
|
2109
|
+
cpdef key_may_exist(self, bytes key, cpp_bool fetch = False, ColumnFamilyHandle column_family = None):
|
|
2110
|
+
cdef string value
|
|
2111
|
+
cdef cpp_bool value_found
|
|
2112
|
+
cdef cpp_bool exists
|
|
2113
|
+
cdef options.ReadOptions opts
|
|
2114
|
+
cdef Slice c_key
|
|
2115
|
+
cdef db.ColumnFamilyHandle* cf_handle = self.db.DefaultColumnFamily()
|
|
2116
|
+
|
|
2117
|
+
if column_family is not None:
|
|
2118
|
+
cf_handle = column_family.get_handle()
|
|
2119
|
+
|
|
2120
|
+
c_key = bytes_to_slice(key)
|
|
2121
|
+
exists = False
|
|
2122
|
+
|
|
2123
|
+
if fetch:
|
|
2124
|
+
value_found = False
|
|
2125
|
+
with nogil:
|
|
2126
|
+
exists = self.db.KeyMayExist(
|
|
2127
|
+
opts,
|
|
2128
|
+
cf_handle,
|
|
2129
|
+
c_key,
|
|
2130
|
+
cython.address(value),
|
|
2131
|
+
cython.address(value_found))
|
|
2132
|
+
|
|
2133
|
+
if exists:
|
|
2134
|
+
if value_found:
|
|
2135
|
+
return (True, string_to_bytes(value))
|
|
2136
|
+
else:
|
|
2137
|
+
return (True, None)
|
|
2138
|
+
else:
|
|
2139
|
+
return (False, None)
|
|
2140
|
+
else:
|
|
2141
|
+
with nogil:
|
|
2142
|
+
exists = self.db.KeyMayExist(
|
|
2143
|
+
opts,
|
|
2144
|
+
cf_handle,
|
|
2145
|
+
c_key,
|
|
2146
|
+
cython.address(value))
|
|
2147
|
+
|
|
2148
|
+
return (exists, None)
|
|
2149
|
+
|
|
2150
|
+
cpdef Iterator iterkeys(self, ColumnFamilyHandle column_family = None):
|
|
2151
|
+
cdef options.ReadOptions opts
|
|
2152
|
+
cdef KeysIterator it
|
|
2153
|
+
cdef db.ColumnFamilyHandle* cf_handle = self.db.DefaultColumnFamily()
|
|
2154
|
+
if column_family is not None:
|
|
2155
|
+
cf_handle = column_family.get_handle()
|
|
2156
|
+
|
|
2157
|
+
it = KeysIterator(self)
|
|
2158
|
+
it.owner = self
|
|
2159
|
+
|
|
2160
|
+
with nogil:
|
|
2161
|
+
it.ptr = self.db.NewIterator(opts, cf_handle)
|
|
2162
|
+
return it
|
|
2163
|
+
|
|
2164
|
+
cpdef Iterator itervalues(self, ColumnFamilyHandle column_family = None):
|
|
2165
|
+
cdef options.ReadOptions opts
|
|
2166
|
+
cdef ValuesIterator it
|
|
2167
|
+
cdef db.ColumnFamilyHandle* cf_handle = self.db.DefaultColumnFamily()
|
|
2168
|
+
if column_family is not None:
|
|
2169
|
+
cf_handle = column_family.get_handle()
|
|
2170
|
+
|
|
2171
|
+
it = ValuesIterator(self)
|
|
2172
|
+
it.owner = self
|
|
2173
|
+
|
|
2174
|
+
with nogil:
|
|
2175
|
+
it.ptr = self.db.NewIterator(opts, cf_handle)
|
|
2176
|
+
return it
|
|
2177
|
+
|
|
2178
|
+
cpdef Iterator iteritems(self, ColumnFamilyHandle column_family = None):
|
|
2179
|
+
cdef options.ReadOptions opts
|
|
2180
|
+
cdef ItemsIterator it
|
|
2181
|
+
cdef db.ColumnFamilyHandle* cf_handle = self.db.DefaultColumnFamily()
|
|
2182
|
+
if column_family is not None:
|
|
2183
|
+
cf_handle = column_family.get_handle()
|
|
2184
|
+
|
|
2185
|
+
it = ItemsIterator.__new__(ItemsIterator)
|
|
2186
|
+
it.db = self
|
|
2187
|
+
it.owner = self
|
|
2188
|
+
|
|
2189
|
+
with nogil:
|
|
2190
|
+
it.ptr = self.db.NewIterator(opts, cf_handle)
|
|
2191
|
+
return it
|
|
2192
|
+
|
|
2193
|
+
cpdef iterskeys(self, column_families):
|
|
2194
|
+
cdef vector[db.Iterator*] iters
|
|
2195
|
+
iters.resize(len(column_families))
|
|
2196
|
+
cdef options.ReadOptions opts
|
|
2197
|
+
cdef db.Iterator* it_ptr
|
|
2198
|
+
cdef KeysIterator it
|
|
2199
|
+
cdef db.ColumnFamilyHandle* cf_handle
|
|
2200
|
+
cdef vector[db.ColumnFamilyHandle*] cf_handles
|
|
2201
|
+
|
|
2202
|
+
for column_family in column_families:
|
|
2203
|
+
cf_handle = (<ColumnFamilyHandle?>column_family).get_handle()
|
|
2204
|
+
cf_handles.push_back(cf_handle)
|
|
2205
|
+
|
|
2206
|
+
with nogil:
|
|
2207
|
+
self.db.NewIterators(opts, cf_handles, &iters)
|
|
2208
|
+
|
|
2209
|
+
cf_iter = iter(column_families)
|
|
2210
|
+
cdef list ret = []
|
|
2211
|
+
for it_ptr in iters:
|
|
2212
|
+
it = KeysIterator(self, next(cf_iter))
|
|
2213
|
+
it.ptr = it_ptr
|
|
2214
|
+
it.owner = self
|
|
2215
|
+
ret.append(it)
|
|
2216
|
+
return ret
|
|
2217
|
+
|
|
2218
|
+
cpdef itersvalues(self, column_families):
|
|
2219
|
+
cdef vector[db.Iterator*] iters
|
|
2220
|
+
iters.resize(len(column_families))
|
|
2221
|
+
cdef options.ReadOptions opts
|
|
2222
|
+
cdef db.Iterator* it_ptr
|
|
2223
|
+
cdef ValuesIterator it
|
|
2224
|
+
cdef db.ColumnFamilyHandle* cf_handle
|
|
2225
|
+
cdef vector[db.ColumnFamilyHandle*] cf_handles
|
|
2226
|
+
|
|
2227
|
+
for column_family in column_families:
|
|
2228
|
+
cf_handle = (<ColumnFamilyHandle?>column_family).get_handle()
|
|
2229
|
+
cf_handles.push_back(cf_handle)
|
|
2230
|
+
|
|
2231
|
+
with nogil:
|
|
2232
|
+
self.db.NewIterators(opts, cf_handles, &iters)
|
|
2233
|
+
|
|
2234
|
+
cdef list ret = []
|
|
2235
|
+
for it_ptr in iters:
|
|
2236
|
+
it = ValuesIterator(self)
|
|
2237
|
+
it.ptr = it_ptr
|
|
2238
|
+
it.owner = self
|
|
2239
|
+
ret.append(it)
|
|
2240
|
+
return ret
|
|
2241
|
+
|
|
2242
|
+
cpdef itersitems(self, column_families):
|
|
2243
|
+
cdef vector[db.Iterator*] iters
|
|
2244
|
+
iters.resize(len(column_families))
|
|
2245
|
+
cdef options.ReadOptions opts
|
|
2246
|
+
cdef db.Iterator* it_ptr
|
|
2247
|
+
cdef ItemsIterator it
|
|
2248
|
+
cdef db.ColumnFamilyHandle* cf_handle
|
|
2249
|
+
cdef vector[db.ColumnFamilyHandle*] cf_handles
|
|
2250
|
+
|
|
2251
|
+
for column_family in column_families:
|
|
2252
|
+
cf_handle = (<ColumnFamilyHandle?>column_family).get_handle()
|
|
2253
|
+
cf_handles.push_back(cf_handle)
|
|
2254
|
+
|
|
2255
|
+
with nogil:
|
|
2256
|
+
self.db.NewIterators(opts, cf_handles, &iters)
|
|
2257
|
+
|
|
2258
|
+
|
|
2259
|
+
cf_iter = iter(column_families)
|
|
2260
|
+
cdef list ret = []
|
|
2261
|
+
for it_ptr in iters:
|
|
2262
|
+
it = ItemsIterator(self, next(cf_iter))
|
|
2263
|
+
it.ptr = it_ptr
|
|
2264
|
+
it.owner = self
|
|
2265
|
+
ret.append(it)
|
|
2266
|
+
return ret
|
|
2267
|
+
|
|
2268
|
+
cpdef snapshot(self):
|
|
2269
|
+
return Snapshot(self)
|
|
2270
|
+
|
|
2271
|
+
cpdef get_property(self, prop, ColumnFamilyHandle column_family = None):
|
|
2272
|
+
cdef string value
|
|
2273
|
+
cdef Slice c_prop = bytes_to_slice(prop)
|
|
2274
|
+
cdef cpp_bool ret = False
|
|
2275
|
+
cdef db.ColumnFamilyHandle* cf_handle = self.db.DefaultColumnFamily()
|
|
2276
|
+
if column_family:
|
|
2277
|
+
cf_handle = column_family.get_handle()
|
|
2278
|
+
|
|
2279
|
+
with nogil:
|
|
2280
|
+
ret = self.db.GetProperty(cf_handle, c_prop, cython.address(value))
|
|
2281
|
+
|
|
2282
|
+
if ret:
|
|
2283
|
+
return string_to_bytes(value)
|
|
2284
|
+
else:
|
|
2285
|
+
return None
|
|
2286
|
+
|
|
2287
|
+
cpdef try_catch_up_with_primary(self):
|
|
2288
|
+
self.db.TryCatchUpWithPrimary()
|
|
2289
|
+
|
|
2290
|
+
cpdef get_live_files_metadata(self):
|
|
2291
|
+
cdef vector[db.LiveFileMetaData] metadata
|
|
2292
|
+
|
|
2293
|
+
with nogil:
|
|
2294
|
+
self.db.GetLiveFilesMetaData(cython.address(metadata))
|
|
2295
|
+
|
|
2296
|
+
ret = []
|
|
2297
|
+
for ob in metadata:
|
|
2298
|
+
t = {}
|
|
2299
|
+
t['name'] = string_to_path(ob.name)
|
|
2300
|
+
t['level'] = ob.level
|
|
2301
|
+
t['size'] = ob.size
|
|
2302
|
+
t['smallestkey'] = string_to_bytes(ob.smallestkey)
|
|
2303
|
+
t['largestkey'] = string_to_bytes(ob.largestkey)
|
|
2304
|
+
t['smallest_seqno'] = ob.smallest_seqno
|
|
2305
|
+
t['largest_seqno'] = ob.largest_seqno
|
|
2306
|
+
|
|
2307
|
+
ret.append(t)
|
|
2308
|
+
|
|
2309
|
+
return ret
|
|
2310
|
+
|
|
2311
|
+
# TODO replace arguments with a single CompactRangeOptions cython wrapper
|
|
2312
|
+
cpdef void compact_range(self,
|
|
2313
|
+
bytes begin=None,
|
|
2314
|
+
bytes end=None,
|
|
2315
|
+
cpp_bool change_level = False,
|
|
2316
|
+
int target_level = -1,
|
|
2317
|
+
str bottommost_level_compaction = 'if_compaction_filter',
|
|
2318
|
+
ColumnFamilyHandle column_family = None
|
|
2319
|
+
):
|
|
2320
|
+
cdef options.CompactRangeOptions c_options
|
|
2321
|
+
|
|
2322
|
+
c_options.change_level = change_level
|
|
2323
|
+
c_options.target_level = target_level
|
|
2324
|
+
|
|
2325
|
+
blc = bottommost_level_compaction
|
|
2326
|
+
if blc == 'skip':
|
|
2327
|
+
c_options.bottommost_level_compaction = options.blc_skip
|
|
2328
|
+
elif blc == 'if_compaction_filter':
|
|
2329
|
+
c_options.bottommost_level_compaction = options.blc_is_filter
|
|
2330
|
+
elif blc == 'force':
|
|
2331
|
+
c_options.bottommost_level_compaction = options.blc_force
|
|
2332
|
+
else:
|
|
2333
|
+
raise ValueError("bottommost_level_compaction is not valid")
|
|
2334
|
+
|
|
2335
|
+
cdef Status st
|
|
2336
|
+
cdef Slice begin_val
|
|
2337
|
+
cdef Slice end_val
|
|
2338
|
+
|
|
2339
|
+
cdef Slice* begin_ptr
|
|
2340
|
+
cdef Slice* end_ptr
|
|
2341
|
+
|
|
2342
|
+
begin_ptr = NULL
|
|
2343
|
+
end_ptr = NULL
|
|
2344
|
+
|
|
2345
|
+
if begin is not None:
|
|
2346
|
+
begin_val = bytes_to_slice(begin)
|
|
2347
|
+
begin_ptr = cython.address(begin_val)
|
|
2348
|
+
|
|
2349
|
+
if end is not None:
|
|
2350
|
+
end_val = bytes_to_slice(end)
|
|
2351
|
+
end_ptr = cython.address(end_val)
|
|
2352
|
+
|
|
2353
|
+
cdef db.ColumnFamilyHandle* cf_handle = self.db.DefaultColumnFamily()
|
|
2354
|
+
if column_family is not None:
|
|
2355
|
+
cf_handle = column_family.get_handle()
|
|
2356
|
+
|
|
2357
|
+
st = self.db.CompactRange(c_options, cf_handle, begin_ptr, end_ptr)
|
|
2358
|
+
check_status(st)
|
|
2359
|
+
|
|
2360
|
+
@staticmethod
|
|
2361
|
+
def __parse_read_opts(
|
|
2362
|
+
verify_checksums=False,
|
|
2363
|
+
fill_cache=True,
|
|
2364
|
+
snapshot=None,
|
|
2365
|
+
read_tier="all"):
|
|
2366
|
+
|
|
2367
|
+
# TODO: Is this really effiencet ?
|
|
2368
|
+
return locals()
|
|
2369
|
+
|
|
2370
|
+
cdef options.ReadOptions build_read_opts(self, dict py_opts):
|
|
2371
|
+
cdef options.ReadOptions opts
|
|
2372
|
+
opts.verify_checksums = py_opts['verify_checksums']
|
|
2373
|
+
opts.fill_cache = py_opts['fill_cache']
|
|
2374
|
+
if py_opts['snapshot'] is not None:
|
|
2375
|
+
opts.snapshot = (<Snapshot?>(py_opts['snapshot'])).ptr
|
|
2376
|
+
|
|
2377
|
+
if py_opts['read_tier'] == "all":
|
|
2378
|
+
opts.read_tier = options.kReadAllTier
|
|
2379
|
+
elif py_opts['read_tier'] == 'cache':
|
|
2380
|
+
opts.read_tier = options.kBlockCacheTier
|
|
2381
|
+
else:
|
|
2382
|
+
raise ValueError("Invalid read_tier")
|
|
2383
|
+
|
|
2384
|
+
return opts
|
|
2385
|
+
|
|
2386
|
+
property options:
|
|
2387
|
+
def __get__(self):
|
|
2388
|
+
return self.opts
|
|
2389
|
+
|
|
2390
|
+
cpdef create_column_family(self, bytes name, ColumnFamilyOptions copts):
|
|
2391
|
+
cdef db.ColumnFamilyHandle* cf_handle
|
|
2392
|
+
cdef Status st
|
|
2393
|
+
cdef string c_name = name
|
|
2394
|
+
|
|
2395
|
+
for handle in self.cf_handles:
|
|
2396
|
+
if handle.name == name:
|
|
2397
|
+
raise ValueError(f"{name} is already an existing column family")
|
|
2398
|
+
|
|
2399
|
+
if copts.in_use:
|
|
2400
|
+
raise Exception("ColumnFamilyOptions are in_use by another column family")
|
|
2401
|
+
|
|
2402
|
+
copts.in_use = True
|
|
2403
|
+
with nogil:
|
|
2404
|
+
st = self.db.CreateColumnFamily(deref(copts.copts), c_name, &cf_handle)
|
|
2405
|
+
check_status(st)
|
|
2406
|
+
|
|
2407
|
+
handle = _ColumnFamilyHandle.from_handle_ptr(cf_handle)
|
|
2408
|
+
|
|
2409
|
+
self.cf_handles.append(handle)
|
|
2410
|
+
self.cf_options.append(copts)
|
|
2411
|
+
return handle.weakref
|
|
2412
|
+
|
|
2413
|
+
cpdef void drop_column_family(self, ColumnFamilyHandle weak_handle):
|
|
2414
|
+
cdef db.ColumnFamilyHandle* cf_handle
|
|
2415
|
+
cdef ColumnFamilyOptions copts
|
|
2416
|
+
cdef Status st
|
|
2417
|
+
|
|
2418
|
+
cf_handle = weak_handle.get_handle()
|
|
2419
|
+
|
|
2420
|
+
with nogil:
|
|
2421
|
+
st = self.db.DropColumnFamily(cf_handle)
|
|
2422
|
+
check_status(st)
|
|
2423
|
+
|
|
2424
|
+
py_handle = weak_handle._ref()
|
|
2425
|
+
index = self.cf_handles.index(py_handle)
|
|
2426
|
+
copts = self.cf_options.pop(index)
|
|
2427
|
+
del self.cf_handles[index]
|
|
2428
|
+
del py_handle
|
|
2429
|
+
if copts:
|
|
2430
|
+
copts.in_use = False
|
|
2431
|
+
|
|
2432
|
+
|
|
2433
|
+
@cython.no_gc_clear
|
|
2434
|
+
cdef class TransactionDB(DB):
|
|
2435
|
+
def __cinit__(
|
|
2436
|
+
self,
|
|
2437
|
+
db_name,
|
|
2438
|
+
Options opts,
|
|
2439
|
+
TransactionDBOptions txn_db_opts = None,
|
|
2440
|
+
dict column_families = None):
|
|
2441
|
+
cdef Status st
|
|
2442
|
+
cdef string db_path
|
|
2443
|
+
cdef vector[db.ColumnFamilyDescriptor] column_family_descriptors
|
|
2444
|
+
cdef vector[db.ColumnFamilyHandle*] column_family_handles
|
|
2445
|
+
cdef bytes default_cf_name = db.kDefaultColumnFamilyName
|
|
2446
|
+
|
|
2447
|
+
self.txn_db = NULL
|
|
2448
|
+
self.txn_opts = None
|
|
2449
|
+
self.db = NULL
|
|
2450
|
+
self.opts = None
|
|
2451
|
+
self.cf_handles = []
|
|
2452
|
+
self.cf_options = []
|
|
2453
|
+
|
|
2454
|
+
if opts.in_use:
|
|
2455
|
+
raise Exception("Options object is already used by another DB")
|
|
2456
|
+
|
|
2457
|
+
if txn_db_opts is None:
|
|
2458
|
+
txn_db_opts = TransactionDBOptions()
|
|
2459
|
+
|
|
2460
|
+
if txn_db_opts.in_use:
|
|
2461
|
+
raise Exception("TransactionDBOptions object is already used by another DB")
|
|
2462
|
+
|
|
2463
|
+
db_path = path_to_string(db_name)
|
|
2464
|
+
|
|
2465
|
+
if not column_families or default_cf_name not in column_families:
|
|
2466
|
+
column_family_descriptors.push_back(
|
|
2467
|
+
db.ColumnFamilyDescriptor(
|
|
2468
|
+
db.kDefaultColumnFamilyName,
|
|
2469
|
+
options.ColumnFamilyOptions(deref(opts.opts))
|
|
2470
|
+
)
|
|
2471
|
+
)
|
|
2472
|
+
self.cf_options.append(None)
|
|
2473
|
+
|
|
2474
|
+
if column_families:
|
|
2475
|
+
for cf_name, cf_options in column_families.items():
|
|
2476
|
+
if not isinstance(cf_name, bytes):
|
|
2477
|
+
raise TypeError(
|
|
2478
|
+
f"column family name {cf_name!r} is not of type {bytes}!"
|
|
2479
|
+
)
|
|
2480
|
+
if not isinstance(cf_options, ColumnFamilyOptions):
|
|
2481
|
+
raise TypeError(
|
|
2482
|
+
f"column family options {cf_options!r} is not of type "
|
|
2483
|
+
f"{ColumnFamilyOptions}!"
|
|
2484
|
+
)
|
|
2485
|
+
if (<ColumnFamilyOptions>cf_options).in_use:
|
|
2486
|
+
raise Exception(
|
|
2487
|
+
f"ColumnFamilyOptions object for {cf_name} is already "
|
|
2488
|
+
"used by another Column Family"
|
|
2489
|
+
)
|
|
2490
|
+
(<ColumnFamilyOptions>cf_options).in_use = True
|
|
2491
|
+
column_family_descriptors.push_back(
|
|
2492
|
+
db.ColumnFamilyDescriptor(
|
|
2493
|
+
cf_name,
|
|
2494
|
+
deref((<ColumnFamilyOptions>cf_options).copts)
|
|
2495
|
+
)
|
|
2496
|
+
)
|
|
2497
|
+
self.cf_options.append(cf_options)
|
|
2498
|
+
|
|
2499
|
+
with nogil:
|
|
2500
|
+
st = transaction.TransactionDB_Open_CF(
|
|
2501
|
+
<options.DBOptions&>deref(opts.opts),
|
|
2502
|
+
deref(txn_db_opts.opts),
|
|
2503
|
+
db_path,
|
|
2504
|
+
column_family_descriptors,
|
|
2505
|
+
&column_family_handles,
|
|
2506
|
+
&self.txn_db)
|
|
2507
|
+
|
|
2508
|
+
check_status(st)
|
|
2509
|
+
|
|
2510
|
+
for handle in column_family_handles:
|
|
2511
|
+
wrapper = _ColumnFamilyHandle.from_handle_ptr(handle)
|
|
2512
|
+
self.cf_handles.append(wrapper)
|
|
2513
|
+
|
|
2514
|
+
self.db = <db.DB*>self.txn_db
|
|
2515
|
+
|
|
2516
|
+
cdef shared_ptr[logger.Logger] info_log = self.db.GetOptions(
|
|
2517
|
+
self.db.DefaultColumnFamily()).info_log
|
|
2518
|
+
if opts.py_comparator is not None:
|
|
2519
|
+
opts.py_comparator.set_info_log(info_log)
|
|
2520
|
+
|
|
2521
|
+
if opts.py_table_factory is not None:
|
|
2522
|
+
opts.py_table_factory.set_info_log(info_log)
|
|
2523
|
+
|
|
2524
|
+
if opts.prefix_extractor is not None:
|
|
2525
|
+
opts.py_prefix_extractor.set_info_log(info_log)
|
|
2526
|
+
|
|
2527
|
+
cdef ColumnFamilyOptions copts
|
|
2528
|
+
for idx, copts in enumerate(self.cf_options):
|
|
2529
|
+
if not copts:
|
|
2530
|
+
continue
|
|
2531
|
+
|
|
2532
|
+
info_log = self.db.GetOptions(column_family_handles[idx]).info_log
|
|
2533
|
+
|
|
2534
|
+
if copts.py_comparator is not None:
|
|
2535
|
+
copts.py_comparator.set_info_log(info_log)
|
|
2536
|
+
|
|
2537
|
+
if copts.py_table_factory is not None:
|
|
2538
|
+
copts.py_table_factory.set_info_log(info_log)
|
|
2539
|
+
|
|
2540
|
+
if copts.py_prefix_extractor is not None:
|
|
2541
|
+
copts.py_prefix_extractor.set_info_log(info_log)
|
|
2542
|
+
|
|
2543
|
+
self.opts = opts
|
|
2544
|
+
self.opts.in_use = True
|
|
2545
|
+
self.txn_opts = txn_db_opts
|
|
2546
|
+
self.txn_opts.in_use = True
|
|
2547
|
+
|
|
2548
|
+
cpdef begin_transaction(
|
|
2549
|
+
self,
|
|
2550
|
+
TransactionOptions txn_options = None,
|
|
2551
|
+
dict write_options = None,
|
|
2552
|
+
Transaction reuse = None):
|
|
2553
|
+
|
|
2554
|
+
if self.txn_db == NULL:
|
|
2555
|
+
raise RuntimeError("TransactionDB is closed")
|
|
2556
|
+
|
|
2557
|
+
cdef options.WriteOptions wopts
|
|
2558
|
+
wopts.sync = False
|
|
2559
|
+
wopts.disableWAL = False
|
|
2560
|
+
|
|
2561
|
+
if write_options is not None:
|
|
2562
|
+
if 'sync' in write_options:
|
|
2563
|
+
wopts.sync = write_options['sync']
|
|
2564
|
+
if 'disable_wal' in write_options:
|
|
2565
|
+
wopts.disableWAL = write_options['disable_wal']
|
|
2566
|
+
if 'disableWAL' in write_options:
|
|
2567
|
+
wopts.disableWAL = write_options['disableWAL']
|
|
2568
|
+
|
|
2569
|
+
cdef transaction.TransactionOptions stack_opts = transaction.TransactionOptions()
|
|
2570
|
+
cdef transaction.TransactionOptions* txn_opts_ptr
|
|
2571
|
+
|
|
2572
|
+
if txn_options is not None:
|
|
2573
|
+
if txn_options.opts == NULL:
|
|
2574
|
+
raise ValueError("TransactionOptions is invalid")
|
|
2575
|
+
txn_opts_ptr = txn_options.opts
|
|
2576
|
+
else:
|
|
2577
|
+
txn_opts_ptr = cython.address(stack_opts)
|
|
2578
|
+
|
|
2579
|
+
cdef transaction.Transaction* raw_txn = NULL
|
|
2580
|
+
|
|
2581
|
+
if reuse is not None:
|
|
2582
|
+
if reuse.txn == NULL:
|
|
2583
|
+
raise ValueError("Reuse transaction handle is closed")
|
|
2584
|
+
if reuse.db is not self:
|
|
2585
|
+
raise ValueError("Reuse transaction belongs to a different TransactionDB")
|
|
2586
|
+
raw_txn = self.txn_db.BeginTransaction(
|
|
2587
|
+
wopts,
|
|
2588
|
+
deref(txn_opts_ptr),
|
|
2589
|
+
reuse.txn)
|
|
2590
|
+
if raw_txn == NULL:
|
|
2591
|
+
raise RuntimeError("BeginTransaction returned NULL")
|
|
2592
|
+
reuse.txn = raw_txn
|
|
2593
|
+
reuse.db = self
|
|
2594
|
+
reuse.closed = False
|
|
2595
|
+
return reuse
|
|
2596
|
+
|
|
2597
|
+
raw_txn = self.txn_db.BeginTransaction(
|
|
2598
|
+
wopts,
|
|
2599
|
+
deref(txn_opts_ptr))
|
|
2600
|
+
|
|
2601
|
+
if raw_txn == NULL:
|
|
2602
|
+
raise RuntimeError("BeginTransaction returned NULL")
|
|
2603
|
+
|
|
2604
|
+
cdef Transaction txn = Transaction.__new__(Transaction)
|
|
2605
|
+
txn.txn = raw_txn
|
|
2606
|
+
txn.db = self
|
|
2607
|
+
txn.closed = False
|
|
2608
|
+
return txn
|
|
2609
|
+
|
|
2610
|
+
def __dealloc__(self):
|
|
2611
|
+
# CRITICAL: NO RETURN STATEMENT
|
|
2612
|
+
self.close()
|
|
2613
|
+
|
|
2614
|
+
cpdef void close(self):
|
|
2615
|
+
# Clear handles first
|
|
2616
|
+
self.cf_handles.clear()
|
|
2617
|
+
|
|
2618
|
+
# Delete the C++ object ONCE
|
|
2619
|
+
if self.txn_db != NULL:
|
|
2620
|
+
with nogil:
|
|
2621
|
+
del self.txn_db
|
|
2622
|
+
self.txn_db = NULL
|
|
2623
|
+
|
|
2624
|
+
# CRITICAL: Set aliased pointer to NULL
|
|
2625
|
+
# This prevents parent from trying to delete
|
|
2626
|
+
self.db = NULL
|
|
2627
|
+
|
|
2628
|
+
# Release options
|
|
2629
|
+
if self.opts is not None:
|
|
2630
|
+
self.opts.in_use = False
|
|
2631
|
+
|
|
2632
|
+
@cython.no_gc_clear
|
|
2633
|
+
cdef class Transaction(object):
|
|
2634
|
+
# pxd should define:
|
|
2635
|
+
# cdef transaction.Transaction* txn
|
|
2636
|
+
# cdef object db # Reference to TransactionDB
|
|
2637
|
+
# cdef cpp_bool closed
|
|
2638
|
+
|
|
2639
|
+
def __cinit__(self):
|
|
2640
|
+
self.txn = NULL
|
|
2641
|
+
self.db = None
|
|
2642
|
+
self.closed = True
|
|
2643
|
+
|
|
2644
|
+
def __dealloc__(self):
|
|
2645
|
+
# If still open, rollback. RocksDB handles deletion after rollback.
|
|
2646
|
+
if self.txn != NULL and not self.closed:
|
|
2647
|
+
self.txn.Rollback()
|
|
2648
|
+
self.txn = NULL
|
|
2649
|
+
|
|
2650
|
+
cpdef void close(self):
|
|
2651
|
+
"""Close the transaction by rolling it back."""
|
|
2652
|
+
if not self.closed:
|
|
2653
|
+
self.rollback()
|
|
2654
|
+
self.closed = True
|
|
2655
|
+
|
|
2656
|
+
cdef void _ensure_open(self):
|
|
2657
|
+
if self.txn == NULL or self.closed:
|
|
2658
|
+
raise RuntimeError("Transaction is closed")
|
|
2659
|
+
if self.db is None or (<TransactionDB>self.db).txn_db == NULL:
|
|
2660
|
+
raise RuntimeError("Parent TransactionDB is closed")
|
|
2661
|
+
|
|
2662
|
+
cpdef void commit(self):
|
|
2663
|
+
self._ensure_open()
|
|
2664
|
+
cdef Status st
|
|
2665
|
+
st = self.txn.Commit()
|
|
2666
|
+
self.closed = True
|
|
2667
|
+
self.txn = NULL # Pointer invalid after commit
|
|
2668
|
+
check_status(st)
|
|
2669
|
+
|
|
2670
|
+
cpdef void rollback(self):
|
|
2671
|
+
if self.closed:
|
|
2672
|
+
return # Idempotent
|
|
2673
|
+
if self.txn == NULL:
|
|
2674
|
+
return
|
|
2675
|
+
cdef Status st
|
|
2676
|
+
st = self.txn.Rollback()
|
|
2677
|
+
self.closed = True
|
|
2678
|
+
self.txn = NULL # Pointer invalid after rollback
|
|
2679
|
+
check_status(st)
|
|
2680
|
+
|
|
2681
|
+
cpdef void prepare(self):
|
|
2682
|
+
self._ensure_open()
|
|
2683
|
+
cdef Status st
|
|
2684
|
+
st = self.txn.Prepare()
|
|
2685
|
+
check_status(st)
|
|
2686
|
+
|
|
2687
|
+
cpdef void set_snapshot(self):
|
|
2688
|
+
self._ensure_open()
|
|
2689
|
+
self.txn.SetSnapshot()
|
|
2690
|
+
|
|
2691
|
+
cpdef void clear_snapshot(self):
|
|
2692
|
+
self._ensure_open()
|
|
2693
|
+
self.txn.ClearSnapshot()
|
|
2694
|
+
|
|
2695
|
+
cpdef snapshot(self):
|
|
2696
|
+
self._ensure_open()
|
|
2697
|
+
cdef const snapshot.Snapshot* ptr = self.txn.GetSnapshot()
|
|
2698
|
+
if ptr == NULL:
|
|
2699
|
+
return None
|
|
2700
|
+
return TransactionSnapshot(self, <size_t><void*>ptr)
|
|
2701
|
+
|
|
2702
|
+
cpdef void save_point(self):
|
|
2703
|
+
self._ensure_open()
|
|
2704
|
+
self.txn.SetSavePoint()
|
|
2705
|
+
|
|
2706
|
+
cpdef void rollback_to_save_point(self):
|
|
2707
|
+
self._ensure_open()
|
|
2708
|
+
cdef Status st
|
|
2709
|
+
st = self.txn.RollbackToSavePoint()
|
|
2710
|
+
check_status(st)
|
|
2711
|
+
|
|
2712
|
+
cpdef void pop_save_point(self):
|
|
2713
|
+
self._ensure_open()
|
|
2714
|
+
cdef Status st
|
|
2715
|
+
st = self.txn.PopSavePoint()
|
|
2716
|
+
check_status(st)
|
|
2717
|
+
|
|
2718
|
+
cpdef set_name(self, name):
|
|
2719
|
+
self._ensure_open()
|
|
2720
|
+
cdef string c_name
|
|
2721
|
+
if isinstance(name, bytes):
|
|
2722
|
+
c_name = bytes_to_string(name)
|
|
2723
|
+
elif isinstance(name, str):
|
|
2724
|
+
c_name = bytes_to_string(name.encode('utf-8'))
|
|
2725
|
+
else:
|
|
2726
|
+
raise TypeError("Transaction name must be bytes or str")
|
|
2727
|
+
|
|
2728
|
+
cdef Status st
|
|
2729
|
+
st = self.txn.SetName(c_name)
|
|
2730
|
+
check_status(st)
|
|
2731
|
+
|
|
2732
|
+
cpdef get_name(self):
|
|
2733
|
+
self._ensure_open()
|
|
2734
|
+
cdef string name = self.txn.GetName()
|
|
2735
|
+
return string_to_bytes(name).decode('utf-8', 'ignore')
|
|
2736
|
+
|
|
2737
|
+
cpdef get_id(self):
|
|
2738
|
+
self._ensure_open()
|
|
2739
|
+
return self.txn.GetID()
|
|
2740
|
+
|
|
2741
|
+
cpdef void put(self, bytes key, bytes value, ColumnFamilyHandle column_family = None, cpp_bool assume_tracked = False):
|
|
2742
|
+
self._ensure_open()
|
|
2743
|
+
cdef Status st
|
|
2744
|
+
cdef Slice c_key = bytes_to_slice(key)
|
|
2745
|
+
cdef Slice c_value = bytes_to_slice(value)
|
|
2746
|
+
cdef db.ColumnFamilyHandle* cf_handle
|
|
2747
|
+
if column_family is not None:
|
|
2748
|
+
cf_handle = column_family.get_handle()
|
|
2749
|
+
st = self.txn.Put(cf_handle, c_key, c_value, assume_tracked)
|
|
2750
|
+
else:
|
|
2751
|
+
st = self.txn.Put(c_key, c_value)
|
|
2752
|
+
check_status(st)
|
|
2753
|
+
|
|
2754
|
+
cpdef void merge(self, bytes key, bytes value, ColumnFamilyHandle column_family = None, cpp_bool assume_tracked = False):
|
|
2755
|
+
self._ensure_open()
|
|
2756
|
+
cdef Status st
|
|
2757
|
+
cdef Slice c_key = bytes_to_slice(key)
|
|
2758
|
+
cdef Slice c_value = bytes_to_slice(value)
|
|
2759
|
+
cdef db.ColumnFamilyHandle* cf_handle
|
|
2760
|
+
if column_family is not None:
|
|
2761
|
+
cf_handle = column_family.get_handle()
|
|
2762
|
+
st = self.txn.Merge(cf_handle, c_key, c_value, assume_tracked)
|
|
2763
|
+
else:
|
|
2764
|
+
st = self.txn.Merge(c_key, c_value)
|
|
2765
|
+
check_status(st)
|
|
2766
|
+
|
|
2767
|
+
cpdef void delete_single(self, bytes key, ColumnFamilyHandle column_family = None, cpp_bool assume_tracked = False):
|
|
2768
|
+
self._ensure_open()
|
|
2769
|
+
cdef Status st
|
|
2770
|
+
cdef Slice c_key = bytes_to_slice(key)
|
|
2771
|
+
cdef db.ColumnFamilyHandle* cf_handle
|
|
2772
|
+
if column_family is not None:
|
|
2773
|
+
cf_handle = column_family.get_handle()
|
|
2774
|
+
st = self.txn.Delete(cf_handle, c_key, assume_tracked)
|
|
2775
|
+
else:
|
|
2776
|
+
st = self.txn.Delete(c_key)
|
|
2777
|
+
check_status(st)
|
|
2778
|
+
|
|
2779
|
+
cpdef get(self, bytes key, ColumnFamilyHandle column_family = None):
|
|
2780
|
+
self._ensure_open()
|
|
2781
|
+
cdef Status st
|
|
2782
|
+
cdef string res
|
|
2783
|
+
cdef options.ReadOptions opts
|
|
2784
|
+
cdef db.ColumnFamilyHandle* cf_handle = self.db.db.DefaultColumnFamily()
|
|
2785
|
+
if column_family is not None:
|
|
2786
|
+
cf_handle = column_family.get_handle()
|
|
2787
|
+
st = self.txn.Get(opts, cf_handle, bytes_to_slice(key), cython.address(res))
|
|
2788
|
+
|
|
2789
|
+
if st.ok():
|
|
2790
|
+
return string_to_bytes(res)
|
|
2791
|
+
elif st.IsNotFound():
|
|
2792
|
+
return None
|
|
2793
|
+
else:
|
|
2794
|
+
check_status(st)
|
|
2795
|
+
|
|
2796
|
+
cpdef multi_get(self, keys):
|
|
2797
|
+
self._ensure_open()
|
|
2798
|
+
cdef vector[string] values
|
|
2799
|
+
values.resize(len(keys))
|
|
2800
|
+
|
|
2801
|
+
cdef db.ColumnFamilyHandle* cf_handle
|
|
2802
|
+
cdef vector[db.ColumnFamilyHandle*] cf_handles
|
|
2803
|
+
cdef vector[Slice] c_keys
|
|
2804
|
+
for key in keys:
|
|
2805
|
+
if isinstance(key, tuple):
|
|
2806
|
+
py_handle, key = key
|
|
2807
|
+
cf_handle = (<ColumnFamilyHandle?>py_handle).get_handle()
|
|
2808
|
+
else:
|
|
2809
|
+
cf_handle = self.db.db.DefaultColumnFamily()
|
|
2810
|
+
c_keys.push_back(bytes_to_slice(key))
|
|
2811
|
+
cf_handles.push_back(cf_handle)
|
|
2812
|
+
|
|
2813
|
+
cdef options.ReadOptions opts
|
|
2814
|
+
cdef vector[Status] res
|
|
2815
|
+
|
|
2816
|
+
res = self.txn.MultiGet(
|
|
2817
|
+
opts,
|
|
2818
|
+
cf_handles,
|
|
2819
|
+
c_keys,
|
|
2820
|
+
cython.address(values))
|
|
2821
|
+
|
|
2822
|
+
cdef dict ret_dict = {}
|
|
2823
|
+
for index in range(len(keys)):
|
|
2824
|
+
if res[index].ok():
|
|
2825
|
+
ret_dict[keys[index]] = string_to_bytes(values[index])
|
|
2826
|
+
elif res[index].IsNotFound():
|
|
2827
|
+
ret_dict[keys[index]] = None
|
|
2828
|
+
else:
|
|
2829
|
+
check_status(res[index])
|
|
2830
|
+
return ret_dict
|
|
2831
|
+
|
|
2832
|
+
cpdef Iterator iterkeys(self, ColumnFamilyHandle column_family = None):
|
|
2833
|
+
self._ensure_open()
|
|
2834
|
+
cdef options.ReadOptions opts
|
|
2835
|
+
cdef db.ColumnFamilyHandle* cf_handle
|
|
2836
|
+
cdef iterator.Iterator* it_ptr
|
|
2837
|
+
cdef transaction.Transaction* txn_ptr = self.txn
|
|
2838
|
+
cdef KeysIterator it
|
|
2839
|
+
|
|
2840
|
+
if column_family is not None:
|
|
2841
|
+
cf_handle = column_family.get_handle()
|
|
2842
|
+
it_ptr = transaction.Transaction_GetIterator_CF(txn_ptr, opts, cf_handle)
|
|
2843
|
+
else:
|
|
2844
|
+
it_ptr = transaction.Transaction_GetIterator(txn_ptr, opts)
|
|
2845
|
+
|
|
2846
|
+
it = KeysIterator(self.db, column_family)
|
|
2847
|
+
it.owner = self
|
|
2848
|
+
it.ptr = it_ptr
|
|
2849
|
+
return it
|
|
2850
|
+
|
|
2851
|
+
cpdef Iterator itervalues(self, ColumnFamilyHandle column_family = None):
|
|
2852
|
+
self._ensure_open()
|
|
2853
|
+
cdef options.ReadOptions opts
|
|
2854
|
+
cdef db.ColumnFamilyHandle* cf_handle
|
|
2855
|
+
cdef iterator.Iterator* it_ptr
|
|
2856
|
+
cdef transaction.Transaction* txn_ptr = self.txn
|
|
2857
|
+
cdef ValuesIterator it
|
|
2858
|
+
|
|
2859
|
+
if column_family is not None:
|
|
2860
|
+
cf_handle = column_family.get_handle()
|
|
2861
|
+
it_ptr = transaction.Transaction_GetIterator_CF(txn_ptr, opts, cf_handle)
|
|
2862
|
+
else:
|
|
2863
|
+
it_ptr = transaction.Transaction_GetIterator(txn_ptr, opts)
|
|
2864
|
+
|
|
2865
|
+
it = ValuesIterator(self.db, column_family)
|
|
2866
|
+
it.owner = self
|
|
2867
|
+
it.ptr = it_ptr
|
|
2868
|
+
return it
|
|
2869
|
+
|
|
2870
|
+
cpdef Iterator iteritems(self, ColumnFamilyHandle column_family = None):
|
|
2871
|
+
self._ensure_open()
|
|
2872
|
+
cdef options.ReadOptions opts
|
|
2873
|
+
cdef db.ColumnFamilyHandle* cf_handle
|
|
2874
|
+
cdef iterator.Iterator* it_ptr
|
|
2875
|
+
cdef transaction.Transaction* txn_ptr = self.txn
|
|
2876
|
+
cdef ItemsIterator it
|
|
2877
|
+
|
|
2878
|
+
if column_family is not None:
|
|
2879
|
+
cf_handle = column_family.get_handle()
|
|
2880
|
+
it_ptr = transaction.Transaction_GetIterator_CF(txn_ptr, opts, cf_handle)
|
|
2881
|
+
else:
|
|
2882
|
+
it_ptr = transaction.Transaction_GetIterator(txn_ptr, opts)
|
|
2883
|
+
|
|
2884
|
+
it = ItemsIterator.__new__(ItemsIterator)
|
|
2885
|
+
it.db = self.db
|
|
2886
|
+
it.handle = column_family
|
|
2887
|
+
it.owner = self
|
|
2888
|
+
it.ptr = it_ptr
|
|
2889
|
+
return it
|
|
2890
|
+
|
|
2891
|
+
cpdef void disable_indexing(self):
|
|
2892
|
+
self._ensure_open()
|
|
2893
|
+
self.txn.DisableIndexing()
|
|
2894
|
+
|
|
2895
|
+
cpdef void enable_indexing(self):
|
|
2896
|
+
self._ensure_open()
|
|
2897
|
+
self.txn.EnableIndexing()
|
|
2898
|
+
|
|
2899
|
+
|
|
2900
|
+
class TransactionSnapshot:
|
|
2901
|
+
__slots__ = ("transaction", "pointer")
|
|
2902
|
+
|
|
2903
|
+
def __init__(self, transaction, pointer):
|
|
2904
|
+
self.transaction = transaction
|
|
2905
|
+
self.pointer = pointer
|
|
2906
|
+
|
|
2907
|
+
def __bool__(self):
|
|
2908
|
+
return bool(self.pointer)
|
|
2909
|
+
|
|
2910
|
+
def __repr__(self):
|
|
2911
|
+
state = "set" if self.pointer else "unset"
|
|
2912
|
+
return f"<TransactionSnapshot {state}>"
|
|
2913
|
+
|
|
2914
|
+
|
|
2915
|
+
cpdef repair_db(db_name, Options opts):
|
|
2916
|
+
cdef Status st
|
|
2917
|
+
cdef string db_path
|
|
2918
|
+
|
|
2919
|
+
db_path = path_to_string(db_name)
|
|
2920
|
+
st = db.RepairDB(db_path, deref(opts.opts))
|
|
2921
|
+
check_status(st)
|
|
2922
|
+
|
|
2923
|
+
|
|
2924
|
+
cpdef list_column_families(db_name, Options opts):
|
|
2925
|
+
cdef Status st
|
|
2926
|
+
cdef string db_path
|
|
2927
|
+
cdef vector[string] column_families
|
|
2928
|
+
|
|
2929
|
+
db_path = path_to_string(db_name)
|
|
2930
|
+
with nogil:
|
|
2931
|
+
st = db.ListColumnFamilies(deref(opts.opts), db_path, &column_families)
|
|
2932
|
+
check_status(st)
|
|
2933
|
+
|
|
2934
|
+
return column_families
|
|
2935
|
+
|
|
2936
|
+
|
|
2937
|
+
@cython.no_gc_clear
|
|
2938
|
+
cdef class Snapshot(object):
|
|
2939
|
+
# pxd defines:
|
|
2940
|
+
# cdef const snapshot.Snapshot* ptr
|
|
2941
|
+
# cdef DB db
|
|
2942
|
+
|
|
2943
|
+
def __cinit__(self, DB db):
|
|
2944
|
+
self.db = db
|
|
2945
|
+
self.ptr = NULL
|
|
2946
|
+
with nogil:
|
|
2947
|
+
self.ptr = db.db.GetSnapshot()
|
|
2948
|
+
|
|
2949
|
+
def __dealloc__(self):
|
|
2950
|
+
if not self.ptr == NULL:
|
|
2951
|
+
with nogil:
|
|
2952
|
+
self.db.db.ReleaseSnapshot(self.ptr)
|
|
2953
|
+
|
|
2954
|
+
|
|
2955
|
+
cdef class Iterator:
|
|
2956
|
+
def __cinit__(self):
|
|
2957
|
+
self._current_value = None
|
|
2958
|
+
|
|
2959
|
+
def __iter__(self):
|
|
2960
|
+
return self
|
|
2961
|
+
|
|
2962
|
+
def __next__(self):
|
|
2963
|
+
item = self.next()
|
|
2964
|
+
if item is None:
|
|
2965
|
+
raise StopIteration
|
|
2966
|
+
return item
|
|
2967
|
+
|
|
2968
|
+
# NOTE Iterator interface defines sentinel value of `None` so it can't
|
|
2969
|
+
# yield None values. However, one can still overwrite cpython's __next__ instead.
|
|
2970
|
+
cpdef object next(self):
|
|
2971
|
+
return None
|
|
2972
|
+
|
|
2973
|
+
cpdef object get(self):
|
|
2974
|
+
if self._current_value is None:
|
|
2975
|
+
self._current_value = self.next()
|
|
2976
|
+
return self._current_value
|
|
2977
|
+
|
|
2978
|
+
cpdef void skip(self):
|
|
2979
|
+
self._current_value = None
|
|
2980
|
+
|
|
2981
|
+
|
|
2982
|
+
cdef class BaseIterator(Iterator):
|
|
2983
|
+
# pxd defines:
|
|
2984
|
+
# cdef iterator.Iterator* ptr
|
|
2985
|
+
# cdef DB db
|
|
2986
|
+
# cdef ColumnFamilyHandle handle
|
|
2987
|
+
|
|
2988
|
+
def __cinit__(self, DB db = None, ColumnFamilyHandle handle = None):
|
|
2989
|
+
self.db = db
|
|
2990
|
+
self.ptr = NULL
|
|
2991
|
+
self.handle = handle
|
|
2992
|
+
self.owner = db
|
|
2993
|
+
|
|
2994
|
+
def __dealloc__(self):
|
|
2995
|
+
if not self.ptr == NULL:
|
|
2996
|
+
del self.ptr
|
|
2997
|
+
|
|
2998
|
+
cpdef object next(self):
|
|
2999
|
+
if not self.ptr.Valid():
|
|
3000
|
+
return None
|
|
3001
|
+
|
|
3002
|
+
cdef object ret = self.get_ob()
|
|
3003
|
+
with nogil:
|
|
3004
|
+
self.ptr.Next()
|
|
3005
|
+
check_status(self.ptr.status())
|
|
3006
|
+
return ret
|
|
3007
|
+
|
|
3008
|
+
cpdef object get(self):
|
|
3009
|
+
if not self.ptr.Valid():
|
|
3010
|
+
raise ValueError()
|
|
3011
|
+
|
|
3012
|
+
cdef object ret = self.get_ob()
|
|
3013
|
+
return ret
|
|
3014
|
+
|
|
3015
|
+
cpdef void skip(self):
|
|
3016
|
+
if not self.ptr.Valid():
|
|
3017
|
+
raise ValueError()
|
|
3018
|
+
with nogil:
|
|
3019
|
+
self.ptr.Next()
|
|
3020
|
+
check_status(self.ptr.status())
|
|
3021
|
+
|
|
3022
|
+
def __reversed__(self):
|
|
3023
|
+
return ReversedIterator(self)
|
|
3024
|
+
|
|
3025
|
+
cpdef void seek_to_first(self):
|
|
3026
|
+
with nogil:
|
|
3027
|
+
self.ptr.SeekToFirst()
|
|
3028
|
+
check_status(self.ptr.status())
|
|
3029
|
+
|
|
3030
|
+
cpdef void seek_to_last(self):
|
|
3031
|
+
with nogil:
|
|
3032
|
+
self.ptr.SeekToLast()
|
|
3033
|
+
check_status(self.ptr.status())
|
|
3034
|
+
|
|
3035
|
+
cpdef void seek(self, bytes key):
|
|
3036
|
+
cdef Slice c_key = bytes_to_slice(key)
|
|
3037
|
+
with nogil:
|
|
3038
|
+
self.ptr.Seek(c_key)
|
|
3039
|
+
check_status(self.ptr.status())
|
|
3040
|
+
|
|
3041
|
+
cpdef void seek_for_prev(self, bytes key):
|
|
3042
|
+
cdef Slice c_key = bytes_to_slice(key)
|
|
3043
|
+
with nogil:
|
|
3044
|
+
self.ptr.SeekForPrev(c_key)
|
|
3045
|
+
check_status(self.ptr.status())
|
|
3046
|
+
|
|
3047
|
+
cdef object get_ob(self):
|
|
3048
|
+
return None
|
|
3049
|
+
|
|
3050
|
+
|
|
3051
|
+
cdef class KeysIterator(BaseIterator):
|
|
3052
|
+
cdef object get_ob(self):
|
|
3053
|
+
cdef Slice c_key
|
|
3054
|
+
with nogil:
|
|
3055
|
+
c_key = self.ptr.key()
|
|
3056
|
+
check_status(self.ptr.status())
|
|
3057
|
+
return slice_to_bytes(c_key)
|
|
3058
|
+
|
|
3059
|
+
|
|
3060
|
+
cdef class ValuesIterator(BaseIterator):
|
|
3061
|
+
cdef object get_ob(self):
|
|
3062
|
+
cdef Slice c_value
|
|
3063
|
+
with nogil:
|
|
3064
|
+
c_value = self.ptr.value()
|
|
3065
|
+
check_status(self.ptr.status())
|
|
3066
|
+
return slice_to_bytes(c_value)
|
|
3067
|
+
|
|
3068
|
+
|
|
3069
|
+
cdef class ItemsIterator(BaseIterator):
|
|
3070
|
+
cdef object get_ob(self):
|
|
3071
|
+
cdef Slice c_key
|
|
3072
|
+
cdef Slice c_value
|
|
3073
|
+
with nogil:
|
|
3074
|
+
c_key = self.ptr.key()
|
|
3075
|
+
c_value = self.ptr.value()
|
|
3076
|
+
check_status(self.ptr.status())
|
|
3077
|
+
return (slice_to_bytes(c_key), slice_to_bytes(c_value))
|
|
3078
|
+
|
|
3079
|
+
|
|
3080
|
+
cdef class ReversedIterator(object):
|
|
3081
|
+
# pxd defines:
|
|
3082
|
+
# cdef BaseIterator it
|
|
3083
|
+
|
|
3084
|
+
def __cinit__(self, BaseIterator it):
|
|
3085
|
+
self.it = it
|
|
3086
|
+
|
|
3087
|
+
cpdef void seek_to_first(self):
|
|
3088
|
+
self.it.seek_to_first()
|
|
3089
|
+
|
|
3090
|
+
cpdef void seek_to_last(self):
|
|
3091
|
+
self.it.seek_to_last()
|
|
3092
|
+
|
|
3093
|
+
cpdef void seek(self, bytes key):
|
|
3094
|
+
self.it.seek(key)
|
|
3095
|
+
|
|
3096
|
+
cpdef void seek_for_prev(self, bytes key):
|
|
3097
|
+
self.it.seek_for_prev(key)
|
|
3098
|
+
|
|
3099
|
+
cpdef object get(self):
|
|
3100
|
+
return self.it.get()
|
|
3101
|
+
|
|
3102
|
+
def __iter__(self):
|
|
3103
|
+
return self
|
|
3104
|
+
|
|
3105
|
+
def __reversed__(self):
|
|
3106
|
+
return self.it
|
|
3107
|
+
|
|
3108
|
+
def __next__(self):
|
|
3109
|
+
if not self.it.ptr.Valid():
|
|
3110
|
+
raise StopIteration()
|
|
3111
|
+
|
|
3112
|
+
cdef object ret = self.it.get_ob()
|
|
3113
|
+
with nogil:
|
|
3114
|
+
self.it.ptr.Prev()
|
|
3115
|
+
check_status(self.it.ptr.status())
|
|
3116
|
+
return ret
|
|
3117
|
+
|
|
3118
|
+
|
|
3119
|
+
cdef class BackupEngine(object):
|
|
3120
|
+
# pxd defines:
|
|
3121
|
+
# cdef backup.BackupEngine* engine
|
|
3122
|
+
|
|
3123
|
+
def __cinit__(self, backup_dir):
|
|
3124
|
+
cdef Status st
|
|
3125
|
+
cdef string c_backup_dir
|
|
3126
|
+
self.engine = NULL
|
|
3127
|
+
|
|
3128
|
+
c_backup_dir = path_to_string(backup_dir)
|
|
3129
|
+
st = backup.BackupEngine_Open(
|
|
3130
|
+
env.Env_Default(),
|
|
3131
|
+
backup.BackupEngineOptions(c_backup_dir),
|
|
3132
|
+
cython.address(self.engine))
|
|
3133
|
+
|
|
3134
|
+
check_status(st)
|
|
3135
|
+
|
|
3136
|
+
def __dealloc__(self):
|
|
3137
|
+
if not self.engine == NULL:
|
|
3138
|
+
with nogil:
|
|
3139
|
+
del self.engine
|
|
3140
|
+
|
|
3141
|
+
cpdef create_backup(self, DB db, flush_before_backup=False):
|
|
3142
|
+
cdef Status st
|
|
3143
|
+
cdef cpp_bool c_flush_before_backup
|
|
3144
|
+
|
|
3145
|
+
c_flush_before_backup = flush_before_backup
|
|
3146
|
+
|
|
3147
|
+
with nogil:
|
|
3148
|
+
st = self.engine.CreateNewBackup(db.db, c_flush_before_backup)
|
|
3149
|
+
check_status(st)
|
|
3150
|
+
|
|
3151
|
+
cpdef restore_backup(self, backup_id, db_dir, wal_dir):
|
|
3152
|
+
cdef Status st
|
|
3153
|
+
cdef backup.BackupID c_backup_id
|
|
3154
|
+
cdef string c_db_dir
|
|
3155
|
+
cdef string c_wal_dir
|
|
3156
|
+
|
|
3157
|
+
c_backup_id = backup_id
|
|
3158
|
+
c_db_dir = path_to_string(db_dir)
|
|
3159
|
+
c_wal_dir = path_to_string(wal_dir)
|
|
3160
|
+
|
|
3161
|
+
with nogil:
|
|
3162
|
+
st = self.engine.RestoreDBFromBackup(
|
|
3163
|
+
c_backup_id,
|
|
3164
|
+
c_db_dir,
|
|
3165
|
+
c_wal_dir)
|
|
3166
|
+
|
|
3167
|
+
check_status(st)
|
|
3168
|
+
|
|
3169
|
+
cpdef restore_latest_backup(self, db_dir, wal_dir):
|
|
3170
|
+
cdef Status st
|
|
3171
|
+
cdef string c_db_dir
|
|
3172
|
+
cdef string c_wal_dir
|
|
3173
|
+
|
|
3174
|
+
c_db_dir = path_to_string(db_dir)
|
|
3175
|
+
c_wal_dir = path_to_string(wal_dir)
|
|
3176
|
+
|
|
3177
|
+
with nogil:
|
|
3178
|
+
st = self.engine.RestoreDBFromLatestBackup(c_db_dir, c_wal_dir)
|
|
3179
|
+
|
|
3180
|
+
check_status(st)
|
|
3181
|
+
|
|
3182
|
+
cpdef stop_backup(self):
|
|
3183
|
+
with nogil:
|
|
3184
|
+
self.engine.StopBackup()
|
|
3185
|
+
|
|
3186
|
+
cpdef purge_old_backups(self, num_backups_to_keep):
|
|
3187
|
+
cdef Status st
|
|
3188
|
+
cdef uint32_t c_num_backups_to_keep
|
|
3189
|
+
|
|
3190
|
+
c_num_backups_to_keep = num_backups_to_keep
|
|
3191
|
+
|
|
3192
|
+
with nogil:
|
|
3193
|
+
st = self.engine.PurgeOldBackups(c_num_backups_to_keep)
|
|
3194
|
+
check_status(st)
|
|
3195
|
+
|
|
3196
|
+
cpdef delete_backup(self, backup_id):
|
|
3197
|
+
cdef Status st
|
|
3198
|
+
cdef backup.BackupID c_backup_id
|
|
3199
|
+
|
|
3200
|
+
c_backup_id = backup_id
|
|
3201
|
+
|
|
3202
|
+
with nogil:
|
|
3203
|
+
st = self.engine.DeleteBackup(c_backup_id)
|
|
3204
|
+
|
|
3205
|
+
check_status(st)
|
|
3206
|
+
|
|
3207
|
+
cpdef get_backup_info(self):
|
|
3208
|
+
cdef vector[backup.BackupInfo] backup_info
|
|
3209
|
+
|
|
3210
|
+
with nogil:
|
|
3211
|
+
self.engine.GetBackupInfo(cython.address(backup_info))
|
|
3212
|
+
|
|
3213
|
+
ret = []
|
|
3214
|
+
for ob in backup_info:
|
|
3215
|
+
t = {}
|
|
3216
|
+
t['backup_id'] = ob.backup_id
|
|
3217
|
+
t['timestamp'] = ob.timestamp
|
|
3218
|
+
t['size'] = ob.size
|
|
3219
|
+
ret.append(t)
|
|
3220
|
+
|
|
3221
|
+
return ret
|