sop4py 2.0.0__py3-none-any.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.
- sop/__init__.py +3 -0
- sop/btree.py +612 -0
- sop/call_go.py +304 -0
- sop/context.py +33 -0
- sop/libjsondb_amd64darwin.dylib +0 -0
- sop/libjsondb_amd64darwin.h +120 -0
- sop/libjsondb_amd64linux.h +120 -0
- sop/libjsondb_amd64linux.so +0 -0
- sop/libjsondb_amd64windows.dll +0 -0
- sop/libjsondb_amd64windows.h +120 -0
- sop/libjsondb_arm64darwin.dylib +0 -0
- sop/libjsondb_arm64darwin.h +120 -0
- sop/libjsondb_arm64linux.h +120 -0
- sop/libjsondb_arm64linux.so +0 -0
- sop/redis.py +40 -0
- sop/test_btree.py +479 -0
- sop/test_btree_idx.py +86 -0
- sop/transaction.py +167 -0
- sop4py-2.0.0.dist-info/METADATA +124 -0
- sop4py-2.0.0.dist-info/RECORD +22 -0
- sop4py-2.0.0.dist-info/WHEEL +5 -0
- sop4py-2.0.0.dist-info/top_level.txt +1 -0
sop/test_btree.py
ADDED
|
@@ -0,0 +1,479 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
import unittest
|
|
3
|
+
import transaction
|
|
4
|
+
import btree
|
|
5
|
+
import context
|
|
6
|
+
|
|
7
|
+
from datetime import timedelta
|
|
8
|
+
from redis import *
|
|
9
|
+
|
|
10
|
+
from dataclasses import dataclass
|
|
11
|
+
|
|
12
|
+
# Stores home folder(s). Replication requires two paths, one for active and the 2nd, the passive.
|
|
13
|
+
stores_folders = ("/Users/grecinto/sop_data/disk1", "/Users/grecinto/sop_data/disk2")
|
|
14
|
+
# EC configuration specifies the Erasure Coding parameters like:
|
|
15
|
+
# "data shards count" (2), "parity shards count" (1), folder paths (disk1, disk2, disk3) where the shards &
|
|
16
|
+
# parities data file will be stored. And a flag (True) whether to auto-repair any shard that failed to read.
|
|
17
|
+
ec = {
|
|
18
|
+
# Erasure Config default entry(key="") will allow different B-tree(tables) to share same EC structure.
|
|
19
|
+
"": transaction.ErasureCodingConfig(
|
|
20
|
+
2,
|
|
21
|
+
1,
|
|
22
|
+
(
|
|
23
|
+
"/Users/grecinto/sop_data/disk1",
|
|
24
|
+
"/Users/grecinto/sop_data/disk2",
|
|
25
|
+
"/Users/grecinto/sop_data/disk3",
|
|
26
|
+
),
|
|
27
|
+
True,
|
|
28
|
+
)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
# Run unit tests in cmdline:
|
|
32
|
+
# python3 -m unittest -v
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@dataclass
|
|
36
|
+
class pKey:
|
|
37
|
+
key: str
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@dataclass
|
|
41
|
+
class Person:
|
|
42
|
+
first_name: str
|
|
43
|
+
last_name: str
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
# Transaction Options (to).
|
|
47
|
+
to = transaction.TransationOptions(
|
|
48
|
+
transaction.TransactionMode.ForWriting.value,
|
|
49
|
+
5,
|
|
50
|
+
transaction.MIN_HASH_MOD_VALUE,
|
|
51
|
+
stores_folders,
|
|
52
|
+
ec,
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
# Context object.
|
|
56
|
+
ctx = context.Context()
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class TestBtree(unittest.TestCase):
|
|
60
|
+
def setUpClass():
|
|
61
|
+
|
|
62
|
+
# initialize SOP global Redis connection
|
|
63
|
+
ro = RedisOptions()
|
|
64
|
+
Redis.open_connection(ro)
|
|
65
|
+
|
|
66
|
+
# create the "barstoreec" b-tree store.
|
|
67
|
+
t = transaction.Transaction(ctx, to)
|
|
68
|
+
t.begin()
|
|
69
|
+
|
|
70
|
+
cache = btree.CacheConfig()
|
|
71
|
+
bo = btree.BtreeOptions("barstoreec", True, cache_config=cache)
|
|
72
|
+
bo.set_value_data_size(btree.ValueDataSize.Small)
|
|
73
|
+
|
|
74
|
+
b3 = btree.Btree.new(ctx, bo, t)
|
|
75
|
+
l = [
|
|
76
|
+
btree.Item(1, "foo"),
|
|
77
|
+
]
|
|
78
|
+
b3.add(ctx, l)
|
|
79
|
+
|
|
80
|
+
# commit the transaction to finalize the new store changes.
|
|
81
|
+
t.commit(ctx)
|
|
82
|
+
print("new B3 succeeded")
|
|
83
|
+
|
|
84
|
+
def test_add_if_not_exists(self):
|
|
85
|
+
t = transaction.Transaction(ctx, to)
|
|
86
|
+
t.begin()
|
|
87
|
+
|
|
88
|
+
b3 = btree.Btree.open(ctx, "barstoreec", t)
|
|
89
|
+
l = [
|
|
90
|
+
btree.Item(1, "foo"),
|
|
91
|
+
]
|
|
92
|
+
if b3.add_if_not_exists(ctx, l):
|
|
93
|
+
print("addIfNotExists should have failed.")
|
|
94
|
+
|
|
95
|
+
t.commit(ctx)
|
|
96
|
+
print("test add_if_not_exists")
|
|
97
|
+
|
|
98
|
+
def test_add_if_not_exists_mapkey(self):
|
|
99
|
+
t = transaction.Transaction(ctx, to)
|
|
100
|
+
t.begin()
|
|
101
|
+
|
|
102
|
+
cache = btree.CacheConfig()
|
|
103
|
+
bo = btree.BtreeOptions("barstoreec_mk", True, cache_config=cache)
|
|
104
|
+
bo.set_value_data_size(btree.ValueDataSize.Small)
|
|
105
|
+
bo.is_primitive_key = False
|
|
106
|
+
|
|
107
|
+
b3 = btree.Btree.new(ctx, bo, t)
|
|
108
|
+
|
|
109
|
+
pk = pKey("foo")
|
|
110
|
+
l = [
|
|
111
|
+
btree.Item(pk, "foo"),
|
|
112
|
+
]
|
|
113
|
+
if b3.add_if_not_exists(ctx, l) == False:
|
|
114
|
+
print("addIfNotExistsMapkey should fail.")
|
|
115
|
+
|
|
116
|
+
t.commit(ctx)
|
|
117
|
+
print("test add_if_not_exists")
|
|
118
|
+
|
|
119
|
+
def test_add_if_not_exists_mapkey_fail(self):
|
|
120
|
+
t = transaction.Transaction(ctx, to)
|
|
121
|
+
t.begin()
|
|
122
|
+
|
|
123
|
+
cache = btree.CacheConfig()
|
|
124
|
+
bo = btree.BtreeOptions("barstoreec_mk2", True, cache_config=cache)
|
|
125
|
+
bo.set_value_data_size(btree.ValueDataSize.Small)
|
|
126
|
+
bo.is_primitive_key = False
|
|
127
|
+
|
|
128
|
+
b3 = btree.Btree.new(ctx, bo, t)
|
|
129
|
+
|
|
130
|
+
l = [
|
|
131
|
+
btree.Item(1, "foo"),
|
|
132
|
+
]
|
|
133
|
+
try:
|
|
134
|
+
if b3.add_if_not_exists(ctx, l) == False:
|
|
135
|
+
print("addIfNotExistsMapkey should fail.")
|
|
136
|
+
pytest.fail("SHOULD NOT REACH THIS.")
|
|
137
|
+
except:
|
|
138
|
+
pass
|
|
139
|
+
|
|
140
|
+
t.commit(ctx)
|
|
141
|
+
print("test add_if_not_exists mapkey fail case")
|
|
142
|
+
|
|
143
|
+
def test_get_items(self):
|
|
144
|
+
t = transaction.Transaction(ctx, to)
|
|
145
|
+
t.begin()
|
|
146
|
+
|
|
147
|
+
b3 = btree.Btree.open(ctx, "barstoreec", t)
|
|
148
|
+
res = b3.get_items(
|
|
149
|
+
ctx, btree.PagingInfo(0, 5, direction=btree.PagingDirection.Forward.value)
|
|
150
|
+
)
|
|
151
|
+
print(f"get_items succeeded {res}.")
|
|
152
|
+
|
|
153
|
+
t.commit(ctx)
|
|
154
|
+
|
|
155
|
+
def test_get_keys(self):
|
|
156
|
+
t = transaction.Transaction(ctx, to)
|
|
157
|
+
t.begin()
|
|
158
|
+
|
|
159
|
+
b3 = btree.Btree.open(ctx, "barstoreec", t)
|
|
160
|
+
res = b3.get_keys(
|
|
161
|
+
ctx, btree.PagingInfo(0, 5, direction=btree.PagingDirection.Forward.value)
|
|
162
|
+
)
|
|
163
|
+
print(f"get_keys succeeded {res}.")
|
|
164
|
+
|
|
165
|
+
t.commit(ctx)
|
|
166
|
+
|
|
167
|
+
def test_get_values(self):
|
|
168
|
+
t = transaction.Transaction(ctx, to)
|
|
169
|
+
t.begin()
|
|
170
|
+
|
|
171
|
+
b3 = btree.Btree.open(ctx, "barstoreec", t)
|
|
172
|
+
keys = b3.get_keys(
|
|
173
|
+
ctx, btree.PagingInfo(0, 5, direction=btree.PagingDirection.Forward.value)
|
|
174
|
+
)
|
|
175
|
+
res = b3.get_values(ctx, keys)
|
|
176
|
+
|
|
177
|
+
print(f"get_values succeeded {res}.")
|
|
178
|
+
|
|
179
|
+
t.commit(ctx)
|
|
180
|
+
|
|
181
|
+
def test_find(self):
|
|
182
|
+
t = transaction.Transaction(ctx, to)
|
|
183
|
+
t.begin()
|
|
184
|
+
|
|
185
|
+
b3 = btree.Btree.open(ctx, "barstoreec", t)
|
|
186
|
+
res = b3.find(ctx, 1)
|
|
187
|
+
|
|
188
|
+
print(f"find succeeded {res}.")
|
|
189
|
+
|
|
190
|
+
t.commit(ctx)
|
|
191
|
+
|
|
192
|
+
def test_find_with_id(self):
|
|
193
|
+
t = transaction.Transaction(ctx, to)
|
|
194
|
+
t.begin()
|
|
195
|
+
|
|
196
|
+
b3 = btree.Btree.open(ctx, "barstoreec", t)
|
|
197
|
+
keys = b3.get_keys(
|
|
198
|
+
ctx, btree.PagingInfo(0, 5, direction=btree.PagingDirection.Forward.value)
|
|
199
|
+
)
|
|
200
|
+
res = b3.find_with_id(ctx, keys[0].key, keys[0].id)
|
|
201
|
+
|
|
202
|
+
print(f"find with id succeeded {res}.")
|
|
203
|
+
|
|
204
|
+
t.commit(ctx)
|
|
205
|
+
|
|
206
|
+
def test_goto_first(self):
|
|
207
|
+
t = transaction.Transaction(ctx, to)
|
|
208
|
+
t.begin()
|
|
209
|
+
|
|
210
|
+
b3 = btree.Btree.open(ctx, "barstoreec", t)
|
|
211
|
+
res = b3.first(ctx)
|
|
212
|
+
|
|
213
|
+
print(f"goto first succeeded {res}.")
|
|
214
|
+
t.commit(ctx)
|
|
215
|
+
|
|
216
|
+
def test_goto_last(self):
|
|
217
|
+
t = transaction.Transaction(ctx, to)
|
|
218
|
+
t.begin()
|
|
219
|
+
|
|
220
|
+
b3 = btree.Btree.open(ctx, "barstoreec", t)
|
|
221
|
+
res = b3.last(ctx)
|
|
222
|
+
|
|
223
|
+
print(f"goto last succeeded {res}.")
|
|
224
|
+
t.commit(ctx)
|
|
225
|
+
|
|
226
|
+
def test_is_unique(self):
|
|
227
|
+
t = transaction.Transaction(ctx, to)
|
|
228
|
+
t.begin()
|
|
229
|
+
|
|
230
|
+
b3 = btree.Btree.open(ctx, "barstoreec", t)
|
|
231
|
+
res = b3.is_unique()
|
|
232
|
+
|
|
233
|
+
print(f"is_unique succeeded {res}.")
|
|
234
|
+
t.commit(ctx)
|
|
235
|
+
|
|
236
|
+
def test_count(self):
|
|
237
|
+
t = transaction.Transaction(ctx, to)
|
|
238
|
+
t.begin()
|
|
239
|
+
|
|
240
|
+
b3 = btree.Btree.open(ctx, "barstoreec", t)
|
|
241
|
+
res = b3.count()
|
|
242
|
+
|
|
243
|
+
print(f"count succeeded {res}.")
|
|
244
|
+
t.commit(ctx)
|
|
245
|
+
|
|
246
|
+
def test_get_store_info(self):
|
|
247
|
+
t = transaction.Transaction(ctx, to)
|
|
248
|
+
t.begin()
|
|
249
|
+
|
|
250
|
+
b3 = btree.Btree.open(ctx, "barstoreec", t)
|
|
251
|
+
res = b3.get_store_info()
|
|
252
|
+
|
|
253
|
+
print(f"storeInfo: {res}")
|
|
254
|
+
t.commit(ctx)
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
class TestBtreeMapKey(unittest.TestCase):
|
|
258
|
+
def setUpClass():
|
|
259
|
+
ro = RedisOptions()
|
|
260
|
+
Redis.open_connection(ro)
|
|
261
|
+
|
|
262
|
+
t = transaction.Transaction(ctx, to)
|
|
263
|
+
t.begin()
|
|
264
|
+
|
|
265
|
+
cache = btree.CacheConfig()
|
|
266
|
+
bo = btree.BtreeOptions("foobar", True, cache_config=cache)
|
|
267
|
+
bo.set_value_data_size(btree.ValueDataSize.Small)
|
|
268
|
+
bo.is_primitive_key = False
|
|
269
|
+
|
|
270
|
+
b3 = btree.Btree.new(ctx, bo, t)
|
|
271
|
+
l = [
|
|
272
|
+
btree.Item(pKey(key="123"), "foo"),
|
|
273
|
+
]
|
|
274
|
+
print(f"foobar b3 add result: {b3.add(ctx, l)}")
|
|
275
|
+
|
|
276
|
+
bo = btree.BtreeOptions("person", True, cache_config=cache)
|
|
277
|
+
bo.set_value_data_size(btree.ValueDataSize.Small)
|
|
278
|
+
bo.is_primitive_key = False
|
|
279
|
+
|
|
280
|
+
btree.Btree.new(ctx, bo, t)
|
|
281
|
+
|
|
282
|
+
t.commit(ctx)
|
|
283
|
+
|
|
284
|
+
print("new B3 succeeded")
|
|
285
|
+
|
|
286
|
+
def test_add_if_not_exists(self):
|
|
287
|
+
t = transaction.Transaction(ctx, to)
|
|
288
|
+
t.begin()
|
|
289
|
+
|
|
290
|
+
b3 = btree.Btree.open(ctx, "foobar", t)
|
|
291
|
+
l = [
|
|
292
|
+
btree.Item(pKey(key="123"), "foo"),
|
|
293
|
+
]
|
|
294
|
+
if b3.add_if_not_exists(ctx, l):
|
|
295
|
+
print("addIfNotExists should have failed.")
|
|
296
|
+
|
|
297
|
+
t.commit(ctx)
|
|
298
|
+
print("test add_if_not_exists")
|
|
299
|
+
|
|
300
|
+
def test_get_items(self):
|
|
301
|
+
t = transaction.Transaction(ctx, to)
|
|
302
|
+
t.begin()
|
|
303
|
+
|
|
304
|
+
b3 = btree.Btree.open(ctx, "foobar", t)
|
|
305
|
+
res = b3.get_items(
|
|
306
|
+
ctx, btree.PagingInfo(0, 5, direction=btree.PagingDirection.Forward.value)
|
|
307
|
+
)
|
|
308
|
+
print(f"get_items succeeded {res}.")
|
|
309
|
+
|
|
310
|
+
t.commit(ctx)
|
|
311
|
+
|
|
312
|
+
def test_get_keys(self):
|
|
313
|
+
t = transaction.Transaction(ctx, to)
|
|
314
|
+
t.begin()
|
|
315
|
+
|
|
316
|
+
b3 = btree.Btree.open(ctx, "foobar", t)
|
|
317
|
+
res = b3.get_keys(
|
|
318
|
+
ctx, btree.PagingInfo(0, 5, direction=btree.PagingDirection.Forward.value)
|
|
319
|
+
)
|
|
320
|
+
print(f"get_keys succeeded {res}.")
|
|
321
|
+
|
|
322
|
+
t.commit(ctx)
|
|
323
|
+
|
|
324
|
+
def test_get_values(self):
|
|
325
|
+
t = transaction.Transaction(ctx, to)
|
|
326
|
+
t.begin()
|
|
327
|
+
|
|
328
|
+
b3 = btree.Btree.open(ctx, "foobar", t)
|
|
329
|
+
keys = b3.get_keys(
|
|
330
|
+
ctx, btree.PagingInfo(0, 5, direction=btree.PagingDirection.Forward.value)
|
|
331
|
+
)
|
|
332
|
+
res = b3.get_values(ctx, keys)
|
|
333
|
+
|
|
334
|
+
print(f"get_values succeeded {res}.")
|
|
335
|
+
|
|
336
|
+
t.commit(ctx)
|
|
337
|
+
|
|
338
|
+
def test_find(self):
|
|
339
|
+
t = transaction.Transaction(ctx, to)
|
|
340
|
+
t.begin()
|
|
341
|
+
|
|
342
|
+
b3 = btree.Btree.open(ctx, "foobar", t)
|
|
343
|
+
res = b3.find(ctx, pKey(key="123"))
|
|
344
|
+
|
|
345
|
+
print(f"find succeeded {res}.")
|
|
346
|
+
|
|
347
|
+
t.commit(ctx)
|
|
348
|
+
|
|
349
|
+
def test_find_with_id(self):
|
|
350
|
+
t = transaction.Transaction(ctx, to)
|
|
351
|
+
t.begin()
|
|
352
|
+
|
|
353
|
+
b3 = btree.Btree.open(ctx, "foobar", t)
|
|
354
|
+
keys = b3.get_keys(
|
|
355
|
+
ctx, btree.PagingInfo(0, 5, direction=btree.PagingDirection.Forward.value)
|
|
356
|
+
)
|
|
357
|
+
res = b3.find_with_id(ctx, keys[0].key, keys[0].id)
|
|
358
|
+
|
|
359
|
+
print(f"find with id succeeded {res}.")
|
|
360
|
+
|
|
361
|
+
t.commit(ctx)
|
|
362
|
+
|
|
363
|
+
def test_goto_first(self):
|
|
364
|
+
t = transaction.Transaction(ctx, to)
|
|
365
|
+
t.begin()
|
|
366
|
+
|
|
367
|
+
b3 = btree.Btree.open(ctx, "foobar", t)
|
|
368
|
+
res = b3.first(ctx)
|
|
369
|
+
|
|
370
|
+
print(f"goto first succeeded {res}.")
|
|
371
|
+
t.commit(ctx)
|
|
372
|
+
|
|
373
|
+
def test_goto_last(self):
|
|
374
|
+
t = transaction.Transaction(ctx, to)
|
|
375
|
+
t.begin()
|
|
376
|
+
|
|
377
|
+
b3 = btree.Btree.open(ctx, "foobar", t)
|
|
378
|
+
res = b3.last(ctx)
|
|
379
|
+
|
|
380
|
+
print(f"goto last succeeded {res}.")
|
|
381
|
+
t.commit(ctx)
|
|
382
|
+
|
|
383
|
+
def test_is_unique(self):
|
|
384
|
+
t = transaction.Transaction(ctx, to)
|
|
385
|
+
t.begin()
|
|
386
|
+
|
|
387
|
+
b3 = btree.Btree.open(ctx, "foobar", t)
|
|
388
|
+
res = b3.is_unique()
|
|
389
|
+
|
|
390
|
+
print(f"is_unique succeeded {res}.")
|
|
391
|
+
t.commit(ctx)
|
|
392
|
+
|
|
393
|
+
def test_count(self):
|
|
394
|
+
t = transaction.Transaction(ctx, to)
|
|
395
|
+
t.begin()
|
|
396
|
+
|
|
397
|
+
b3 = btree.Btree.open(ctx, "foobar", t)
|
|
398
|
+
res = b3.count()
|
|
399
|
+
|
|
400
|
+
print(f"count succeeded {res}.")
|
|
401
|
+
t.commit(ctx)
|
|
402
|
+
|
|
403
|
+
def test_get_store_info(self):
|
|
404
|
+
t = transaction.Transaction(ctx, to)
|
|
405
|
+
t.begin()
|
|
406
|
+
|
|
407
|
+
b3 = btree.Btree.open(ctx, "foobar", t)
|
|
408
|
+
res = b3.get_store_info()
|
|
409
|
+
|
|
410
|
+
print(f"storeInfo: {res}")
|
|
411
|
+
t.commit(ctx)
|
|
412
|
+
|
|
413
|
+
def test_add_people(self):
|
|
414
|
+
t = transaction.Transaction(ctx, to)
|
|
415
|
+
t.begin()
|
|
416
|
+
|
|
417
|
+
b3 = btree.Btree.open(ctx, "person", t)
|
|
418
|
+
|
|
419
|
+
# Prepare a batch of 500 Person records.
|
|
420
|
+
l = []
|
|
421
|
+
for i in range(500):
|
|
422
|
+
l.append(btree.Item(pKey(key=f"{i}"), Person(f"joe{i}", "petit")))
|
|
423
|
+
|
|
424
|
+
# Add the batch to the B-tree.
|
|
425
|
+
if not b3.add_if_not_exists(ctx, l):
|
|
426
|
+
print("failed to add list of persons to backend db")
|
|
427
|
+
|
|
428
|
+
t.commit(ctx)
|
|
429
|
+
|
|
430
|
+
def test_get_keys_get_values(self):
|
|
431
|
+
t = transaction.Transaction(ctx, to)
|
|
432
|
+
t.begin()
|
|
433
|
+
|
|
434
|
+
b3 = btree.Btree.open(ctx, "person", t)
|
|
435
|
+
b3.first(ctx)
|
|
436
|
+
keys = b3.get_keys(
|
|
437
|
+
ctx,
|
|
438
|
+
btree.PagingInfo(10, 20, 2, direction=btree.PagingDirection.Forward.value),
|
|
439
|
+
)
|
|
440
|
+
values = b3.get_values(ctx, keys)
|
|
441
|
+
print(f"values: {values}")
|
|
442
|
+
|
|
443
|
+
t.commit(ctx)
|
|
444
|
+
|
|
445
|
+
def test_get_keys_backwards_get_values(self):
|
|
446
|
+
t = transaction.Transaction(ctx, to)
|
|
447
|
+
t.begin()
|
|
448
|
+
|
|
449
|
+
b3 = btree.Btree.open(ctx, "person", t)
|
|
450
|
+
# Position cursor to the last item.
|
|
451
|
+
b3.last(ctx)
|
|
452
|
+
# Navigate to the 200th item backwards then fetch that item & the item previous to it.
|
|
453
|
+
keys = b3.get_keys(
|
|
454
|
+
ctx,
|
|
455
|
+
btree.PagingInfo(10, 20, 2, direction=btree.PagingDirection.Backward.value),
|
|
456
|
+
)
|
|
457
|
+
# Use the returned keys to ask B-tree to fetch the values of these keys.
|
|
458
|
+
values = b3.get_values(ctx, keys)
|
|
459
|
+
print(f"values: {values}")
|
|
460
|
+
|
|
461
|
+
t.commit(ctx)
|
|
462
|
+
|
|
463
|
+
def test_get_keys_over_the_edge_get_values(self):
|
|
464
|
+
t = transaction.Transaction(ctx, to)
|
|
465
|
+
t.begin()
|
|
466
|
+
|
|
467
|
+
b3 = btree.Btree.open(ctx, "person", t)
|
|
468
|
+
b3.first(ctx)
|
|
469
|
+
keys = b3.get_keys(
|
|
470
|
+
ctx,
|
|
471
|
+
# There are 500 records in the DB, navigate to the 490th then fetch last 10 records.
|
|
472
|
+
# Since there are only 10 records after reaching 490 item location, fetching 20 will just return remaining 10 records.
|
|
473
|
+
btree.PagingInfo(49, 10, 20, direction=btree.PagingDirection.Forward.value),
|
|
474
|
+
)
|
|
475
|
+
# Use the returned keys to ask B-tree to fetch the value parts of these keys.
|
|
476
|
+
values = b3.get_values(ctx, keys)
|
|
477
|
+
print(f"values: {values}")
|
|
478
|
+
|
|
479
|
+
t.commit(ctx)
|
sop/test_btree_idx.py
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
import transaction
|
|
3
|
+
import btree
|
|
4
|
+
import context
|
|
5
|
+
|
|
6
|
+
from redis import *
|
|
7
|
+
from test_btree import to
|
|
8
|
+
|
|
9
|
+
from dataclasses import dataclass
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@dataclass
|
|
13
|
+
class Key:
|
|
14
|
+
address1: str
|
|
15
|
+
address2: str
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@dataclass
|
|
19
|
+
class Person:
|
|
20
|
+
first_name: str
|
|
21
|
+
last_name: str
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
# create a context for use in Transaction & B-tree API calls.
|
|
25
|
+
ctx = context.Context()
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class TestBtreeIndexSpecs(unittest.TestCase):
|
|
29
|
+
def setUpClass():
|
|
30
|
+
ro = RedisOptions()
|
|
31
|
+
Redis.open_connection(ro)
|
|
32
|
+
|
|
33
|
+
t = transaction.Transaction(ctx, to)
|
|
34
|
+
t.begin()
|
|
35
|
+
|
|
36
|
+
cache = btree.CacheConfig()
|
|
37
|
+
bo = btree.BtreeOptions("personidx", True, cache_config=cache)
|
|
38
|
+
bo.set_value_data_size(btree.ValueDataSize.Small)
|
|
39
|
+
bo.is_primitive_key = False
|
|
40
|
+
btree.Btree.new(
|
|
41
|
+
ctx,
|
|
42
|
+
bo,
|
|
43
|
+
t,
|
|
44
|
+
# specify the Index fields of the Key class. You control how many fields get included
|
|
45
|
+
# and each field's sort order (asc or desc).
|
|
46
|
+
btree.IndexSpecification(
|
|
47
|
+
index_fields=(
|
|
48
|
+
btree.IndexFieldSpecification(
|
|
49
|
+
"address1", ascending_sort_order=False
|
|
50
|
+
),
|
|
51
|
+
btree.IndexFieldSpecification("address2"),
|
|
52
|
+
)
|
|
53
|
+
),
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
t.commit(ctx)
|
|
57
|
+
|
|
58
|
+
def test_add(self):
|
|
59
|
+
t = transaction.Transaction(ctx, to)
|
|
60
|
+
t.begin()
|
|
61
|
+
|
|
62
|
+
b3 = btree.Btree.open(ctx, "personidx", t)
|
|
63
|
+
|
|
64
|
+
pk = Key(address1="123 main st", address2="Fremont, CA")
|
|
65
|
+
l = [btree.Item(pk, Person(first_name="joe", last_name="petit"))]
|
|
66
|
+
|
|
67
|
+
for i in range(20):
|
|
68
|
+
pk = Key(address1=f"{i}123 main st", address2="Fremont, CA")
|
|
69
|
+
l.append(btree.Item(pk, Person(first_name=f"joe{i}", last_name="petit")))
|
|
70
|
+
|
|
71
|
+
b3.add_if_not_exists(ctx, l)
|
|
72
|
+
|
|
73
|
+
t.commit(ctx)
|
|
74
|
+
|
|
75
|
+
def test_get_items_batch(self):
|
|
76
|
+
t = transaction.Transaction(ctx, to)
|
|
77
|
+
t.begin()
|
|
78
|
+
|
|
79
|
+
b3 = btree.Btree.open(ctx, "personidx", t)
|
|
80
|
+
items = b3.get_items(
|
|
81
|
+
ctx,
|
|
82
|
+
btree.PagingInfo(0, 0, 10, direction=btree.PagingDirection.Forward.value),
|
|
83
|
+
)
|
|
84
|
+
print(f"read items from indexed keyed b-tree {items}")
|
|
85
|
+
|
|
86
|
+
t.commit(ctx)
|