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/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)