zlmdb 25.12.2__cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.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.
Files changed (76) hide show
  1. zlmdb/__init__.py +416 -0
  2. zlmdb/_database.py +990 -0
  3. zlmdb/_errors.py +31 -0
  4. zlmdb/_flatc/__init__.py +105 -0
  5. zlmdb/_lmdb_vendor/__init__.py +37 -0
  6. zlmdb/_lmdb_vendor/__main__.py +25 -0
  7. zlmdb/_lmdb_vendor/_config.py +10 -0
  8. zlmdb/_lmdb_vendor/_lmdb_cffi.cpython-314t-aarch64-linux-gnu.so +0 -0
  9. zlmdb/_lmdb_vendor/cffi.py +2606 -0
  10. zlmdb/_lmdb_vendor/tool.py +670 -0
  11. zlmdb/_meta.py +27 -0
  12. zlmdb/_pmap.py +1667 -0
  13. zlmdb/_schema.py +137 -0
  14. zlmdb/_transaction.py +181 -0
  15. zlmdb/_types.py +1596 -0
  16. zlmdb/_version.py +27 -0
  17. zlmdb/cli.py +41 -0
  18. zlmdb/flatbuffers/__init__.py +60 -0
  19. zlmdb/flatbuffers/_git_version.py +24 -0
  20. zlmdb/flatbuffers/_version.py +17 -0
  21. zlmdb/flatbuffers/builder.py +824 -0
  22. zlmdb/flatbuffers/compat.py +89 -0
  23. zlmdb/flatbuffers/encode.py +43 -0
  24. zlmdb/flatbuffers/flexbuffers.py +1570 -0
  25. zlmdb/flatbuffers/number_types.py +182 -0
  26. zlmdb/flatbuffers/packer.py +42 -0
  27. zlmdb/flatbuffers/reflection/AdvancedFeatures.py +10 -0
  28. zlmdb/flatbuffers/reflection/BaseType.py +25 -0
  29. zlmdb/flatbuffers/reflection/Enum.py +252 -0
  30. zlmdb/flatbuffers/reflection/EnumVal.py +144 -0
  31. zlmdb/flatbuffers/reflection/Field.py +325 -0
  32. zlmdb/flatbuffers/reflection/KeyValue.py +84 -0
  33. zlmdb/flatbuffers/reflection/Object.py +260 -0
  34. zlmdb/flatbuffers/reflection/RPCCall.py +195 -0
  35. zlmdb/flatbuffers/reflection/Schema.py +301 -0
  36. zlmdb/flatbuffers/reflection/SchemaFile.py +112 -0
  37. zlmdb/flatbuffers/reflection/Service.py +213 -0
  38. zlmdb/flatbuffers/reflection/Type.py +148 -0
  39. zlmdb/flatbuffers/reflection/__init__.py +0 -0
  40. zlmdb/flatbuffers/reflection.fbs +156 -0
  41. zlmdb/flatbuffers/table.py +129 -0
  42. zlmdb/flatbuffers/util.py +47 -0
  43. zlmdb/py.typed +0 -0
  44. zlmdb/tests/conftest.py +9 -0
  45. zlmdb/tests/lmdb/__init__.py +0 -0
  46. zlmdb/tests/lmdb/address_book.py +287 -0
  47. zlmdb/tests/lmdb/crash_test.py +339 -0
  48. zlmdb/tests/lmdb/cursor_test.py +333 -0
  49. zlmdb/tests/lmdb/env_test.py +919 -0
  50. zlmdb/tests/lmdb/getmulti_test.py +92 -0
  51. zlmdb/tests/lmdb/iteration_test.py +258 -0
  52. zlmdb/tests/lmdb/package_test.py +70 -0
  53. zlmdb/tests/lmdb/test_lmdb.py +188 -0
  54. zlmdb/tests/lmdb/testlib.py +185 -0
  55. zlmdb/tests/lmdb/tool_test.py +60 -0
  56. zlmdb/tests/lmdb/txn_test.py +575 -0
  57. zlmdb/tests/orm/MNodeLog.py +853 -0
  58. zlmdb/tests/orm/__init__.py +0 -0
  59. zlmdb/tests/orm/_schema_fbs.py +215 -0
  60. zlmdb/tests/orm/_schema_mnode_log.py +1202 -0
  61. zlmdb/tests/orm/_schema_py2.py +250 -0
  62. zlmdb/tests/orm/_schema_py3.py +307 -0
  63. zlmdb/tests/orm/_test_flatbuffers.py +144 -0
  64. zlmdb/tests/orm/_test_serialization.py +144 -0
  65. zlmdb/tests/orm/test_basic.py +217 -0
  66. zlmdb/tests/orm/test_etcd.py +275 -0
  67. zlmdb/tests/orm/test_pmap_indexes.py +466 -0
  68. zlmdb/tests/orm/test_pmap_types.py +90 -0
  69. zlmdb/tests/orm/test_pmaps.py +295 -0
  70. zlmdb/tests/orm/test_select.py +619 -0
  71. zlmdb-25.12.2.dist-info/METADATA +280 -0
  72. zlmdb-25.12.2.dist-info/RECORD +76 -0
  73. zlmdb-25.12.2.dist-info/WHEEL +7 -0
  74. zlmdb-25.12.2.dist-info/entry_points.txt +3 -0
  75. zlmdb-25.12.2.dist-info/licenses/LICENSE +167 -0
  76. zlmdb-25.12.2.dist-info/licenses/NOTICE +41 -0
@@ -0,0 +1,619 @@
1
+ ###############################################################################
2
+ #
3
+ # The MIT License (MIT)
4
+ #
5
+ # Copyright (c) typedef int GmbH
6
+ #
7
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ # of this software and associated documentation files (the "Software"), to deal
9
+ # in the Software without restriction, including without limitation the rights
10
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ # copies of the Software, and to permit persons to whom the Software is
12
+ # furnished to do so, subject to the following conditions:
13
+ #
14
+ # The above copyright notice and this permission notice shall be included in
15
+ # all copies or substantial portions of the Software.
16
+ #
17
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
+ # THE SOFTWARE.
24
+ #
25
+ ###############################################################################
26
+
27
+ import os
28
+ import uuid
29
+ import random
30
+ import struct
31
+ import logging
32
+
33
+ import flatbuffers
34
+ import numpy as np
35
+ import pytest
36
+
37
+ import zlmdb # noqa
38
+
39
+ from _schema_mnode_log import Schema, MNodeLog
40
+
41
+ from time import time_ns
42
+
43
+ import txaio
44
+
45
+ txaio.use_twisted()
46
+
47
+ try:
48
+ from tempfile import TemporaryDirectory
49
+ except ImportError:
50
+ from backports.tempfile import TemporaryDirectory # type:ignore
51
+
52
+ if "COVERAGE_PROCESS_START" in os.environ or "QUICK" in os.environ:
53
+ QUICK = True
54
+ else:
55
+ QUICK = False
56
+
57
+
58
+ @pytest.fixture(scope="function")
59
+ def builder():
60
+ _builder = flatbuffers.Builder(0)
61
+ return _builder
62
+
63
+
64
+ def rfloat():
65
+ return struct.unpack(">f", struct.pack(">f", random.random() * 10**10))[0]
66
+
67
+
68
+ def fill_mnodelog(obj):
69
+ obj.timestamp = np.datetime64(time_ns(), "ns") + np.timedelta64(
70
+ random.randint(1, 120), "s"
71
+ )
72
+ obj.node_id = uuid.uuid4()
73
+ obj.run_id = uuid.uuid4()
74
+ obj.state = random.randint(1, 2)
75
+ obj.ended = obj.timestamp + np.timedelta64(random.randint(1, 120), "s")
76
+ obj.session = random.randint(1, 9007199254740992)
77
+ obj.sent = obj.timestamp
78
+ obj.seq = random.randint(1, 10000)
79
+
80
+ obj.routers = random.randint(1, 32)
81
+ obj.containers = random.randint(1, 32)
82
+ obj.guests = random.randint(1, 32)
83
+ obj.proxies = random.randint(1, 32)
84
+ obj.marketmakers = random.randint(1, 32)
85
+
86
+ obj.cpu_ctx_switches = random.randint(1, 1000000)
87
+
88
+ # we can't just use random() here, since it won't work for roundtrip
89
+ # data checking (eg 33.42830630594208 != 33.428306579589844)
90
+ # obj.cpu_freq = random.random() * 100.
91
+ obj.cpu_freq = rfloat()
92
+
93
+ obj.cpu_guest = rfloat()
94
+ obj.cpu_guest_nice = rfloat()
95
+ obj.cpu_idle = rfloat()
96
+ obj.cpu_interrupts = random.randint(1, 100000)
97
+ obj.cpu_iotwait = rfloat()
98
+ obj.cpu_irq = rfloat()
99
+ obj.cpu_nice = rfloat()
100
+ obj.cpu_soft_interrupts = random.randint(1, 100000)
101
+ obj.cpu_softirq = rfloat()
102
+ obj.cpu_steal = rfloat()
103
+ obj.cpu_system = rfloat()
104
+ obj.cpu_user = rfloat()
105
+
106
+ obj.network_bytes_recv = random.randint(1, 2**32)
107
+ obj.network_bytes_sent = random.randint(1, 2**32)
108
+ obj.network_connection_af_inet = random.randint(1, 1000)
109
+ obj.network_connection_af_inet6 = random.randint(1, 1000)
110
+ obj.network_connection_af_unix = random.randint(1, 1000)
111
+ obj.network_dropin = random.randint(1, 10000)
112
+ obj.network_dropout = random.randint(1, 10000)
113
+ obj.network_errin = random.randint(1, 10000)
114
+ obj.network_errout = random.randint(1, 10000)
115
+ obj.network_packets_recv = random.randint(1, 2**32)
116
+ obj.network_packets_sent = random.randint(1, 2**32)
117
+
118
+ M = 32 * 2**30
119
+ obj.memory_active = random.randint(1, M)
120
+ obj.memory_available = random.randint(1, M)
121
+ obj.memory_buffers = random.randint(1, M)
122
+ obj.memory_cached = random.randint(1, M)
123
+ obj.memory_free = random.randint(1, M)
124
+ obj.memory_inactive = random.randint(1, M)
125
+ obj.memory_percent = rfloat()
126
+ obj.memory_shared = random.randint(1, M)
127
+ obj.memory_slab = random.randint(1, M)
128
+ obj.memory_total = random.randint(1, M)
129
+ obj.memory_used = random.randint(1, M)
130
+
131
+ M = 10 * 10
132
+ obj.disk_busy_time = random.randint(1, M)
133
+ obj.disk_read_bytes = random.randint(1, M)
134
+ obj.disk_read_count = random.randint(1, M)
135
+ obj.disk_read_merged_count = random.randint(1, M)
136
+ obj.disk_read_time = random.randint(1, M)
137
+ obj.disk_write_bytes = random.randint(1, M)
138
+ obj.disk_write_count = random.randint(1, M)
139
+ obj.disk_write_merged_count = random.randint(1, M)
140
+ obj.disk_write_time = random.randint(1, M)
141
+
142
+
143
+ @pytest.fixture(scope="function")
144
+ def mnodelog():
145
+ _mnodelog = MNodeLog()
146
+ fill_mnodelog(_mnodelog)
147
+ return _mnodelog
148
+
149
+
150
+ def test_mnodelog_roundtrip(mnodelog, builder):
151
+ # serialize to bytes (flatbuffers) from python object
152
+ obj = mnodelog.build(builder)
153
+ builder.Finish(obj)
154
+ data = builder.Output()
155
+ assert len(data) == 544
156
+
157
+ # create python object from bytes (flatbuffes)
158
+ _mnodelog = MNodeLog.cast(data)
159
+
160
+ assert mnodelog.timestamp == _mnodelog.timestamp
161
+ assert mnodelog.node_id == _mnodelog.node_id
162
+ assert mnodelog.run_id == _mnodelog.run_id
163
+ assert mnodelog.state == _mnodelog.state
164
+ assert mnodelog.ended == _mnodelog.ended
165
+ assert mnodelog.session == _mnodelog.session
166
+ assert mnodelog.sent == _mnodelog.sent
167
+ assert mnodelog.seq == _mnodelog.seq
168
+
169
+ assert mnodelog.routers == _mnodelog.routers
170
+ assert mnodelog.containers == _mnodelog.containers
171
+ assert mnodelog.guests == _mnodelog.guests
172
+ assert mnodelog.proxies == _mnodelog.proxies
173
+ assert mnodelog.marketmakers == _mnodelog.marketmakers
174
+
175
+ assert mnodelog.cpu_ctx_switches == _mnodelog.cpu_ctx_switches
176
+ assert mnodelog.cpu_freq == _mnodelog.cpu_freq
177
+ assert mnodelog.cpu_guest == _mnodelog.cpu_guest
178
+ assert mnodelog.cpu_guest_nice == _mnodelog.cpu_guest_nice
179
+ assert mnodelog.cpu_idle == _mnodelog.cpu_idle
180
+ assert mnodelog.cpu_interrupts == _mnodelog.cpu_interrupts
181
+ assert mnodelog.cpu_iotwait == _mnodelog.cpu_iotwait
182
+ assert mnodelog.cpu_irq == _mnodelog.cpu_irq
183
+ assert mnodelog.cpu_nice == _mnodelog.cpu_nice
184
+ assert mnodelog.cpu_soft_interrupts == _mnodelog.cpu_soft_interrupts
185
+ assert mnodelog.cpu_softirq == _mnodelog.cpu_softirq
186
+ assert mnodelog.cpu_steal == _mnodelog.cpu_steal
187
+ assert mnodelog.cpu_system == _mnodelog.cpu_system
188
+ assert mnodelog.cpu_user == _mnodelog.cpu_user
189
+
190
+ assert mnodelog.network_bytes_recv == _mnodelog.network_bytes_recv
191
+ assert mnodelog.network_bytes_sent == _mnodelog.network_bytes_sent
192
+ assert mnodelog.network_connection_af_inet == _mnodelog.network_connection_af_inet
193
+ assert mnodelog.network_connection_af_inet6 == _mnodelog.network_connection_af_inet6
194
+ assert mnodelog.network_connection_af_unix == _mnodelog.network_connection_af_unix
195
+ assert mnodelog.network_dropin == _mnodelog.network_dropin
196
+ assert mnodelog.network_dropout == _mnodelog.network_dropout
197
+ assert mnodelog.network_errin == _mnodelog.network_errin
198
+ assert mnodelog.network_errout == _mnodelog.network_errout
199
+ assert mnodelog.network_packets_recv == _mnodelog.network_packets_recv
200
+ assert mnodelog.network_packets_sent == _mnodelog.network_packets_sent
201
+
202
+ assert mnodelog.memory_active == _mnodelog.memory_active
203
+ assert mnodelog.memory_available == _mnodelog.memory_available
204
+ assert mnodelog.memory_buffers == _mnodelog.memory_buffers
205
+ assert mnodelog.memory_cached == _mnodelog.memory_cached
206
+ assert mnodelog.memory_free == _mnodelog.memory_free
207
+ assert mnodelog.memory_inactive == _mnodelog.memory_inactive
208
+ assert mnodelog.memory_percent == _mnodelog.memory_percent
209
+ assert mnodelog.memory_shared == _mnodelog.memory_shared
210
+ assert mnodelog.memory_slab == _mnodelog.memory_slab
211
+ assert mnodelog.memory_total == _mnodelog.memory_total
212
+ assert mnodelog.memory_used == _mnodelog.memory_used
213
+
214
+ assert mnodelog.disk_busy_time == _mnodelog.disk_busy_time
215
+ assert mnodelog.disk_read_bytes == _mnodelog.disk_read_bytes
216
+ assert mnodelog.disk_read_count == _mnodelog.disk_read_count
217
+ assert mnodelog.disk_read_merged_count == _mnodelog.disk_read_merged_count
218
+ assert mnodelog.disk_read_time == _mnodelog.disk_read_time
219
+ assert mnodelog.disk_write_bytes == _mnodelog.disk_write_bytes
220
+ assert mnodelog.disk_write_count == _mnodelog.disk_write_count
221
+ assert mnodelog.disk_write_merged_count == _mnodelog.disk_write_merged_count
222
+ assert mnodelog.disk_write_time == _mnodelog.disk_write_time
223
+
224
+
225
+ def test_mnodelog_insert(N=1000):
226
+ with TemporaryDirectory() as dbpath:
227
+ with zlmdb.Database(dbpath) as db:
228
+ schema = Schema.attach(db)
229
+
230
+ data = {}
231
+
232
+ # insert test data
233
+ #
234
+ with db.begin(write=True) as txn:
235
+ for i in range(N):
236
+ rec = MNodeLog()
237
+ fill_mnodelog(rec)
238
+ key = (rec.timestamp, rec.node_id)
239
+ schema.mnode_logs[txn, key] = rec
240
+
241
+ data[key] = rec
242
+
243
+ # do test scans over inserted data
244
+ #
245
+ with db.begin() as txn:
246
+ cnt = schema.mnode_logs.count(txn)
247
+ assert cnt == N
248
+
249
+ # do a simple full scan and compare to original data
250
+ #
251
+ for mnodelog in schema.mnode_logs.select(txn, return_keys=False):
252
+ key = (mnodelog.timestamp, mnodelog.node_id)
253
+
254
+ _mnodelog = data.get(key, None)
255
+
256
+ # check that we have the record in the original data
257
+ assert _mnodelog
258
+
259
+ # check that the record data is equal to the original data
260
+ assert mnodelog.timestamp == _mnodelog.timestamp
261
+ assert mnodelog.node_id == _mnodelog.node_id
262
+ assert mnodelog.run_id == _mnodelog.run_id
263
+ assert mnodelog.state == _mnodelog.state
264
+ assert mnodelog.ended == _mnodelog.ended
265
+ assert mnodelog.session == _mnodelog.session
266
+ assert mnodelog.sent == _mnodelog.sent
267
+ assert mnodelog.seq == _mnodelog.seq
268
+
269
+ assert mnodelog.routers == _mnodelog.routers
270
+ assert mnodelog.containers == _mnodelog.containers
271
+ assert mnodelog.guests == _mnodelog.guests
272
+ assert mnodelog.proxies == _mnodelog.proxies
273
+ assert mnodelog.marketmakers == _mnodelog.marketmakers
274
+
275
+ assert mnodelog.cpu_ctx_switches == _mnodelog.cpu_ctx_switches
276
+ assert mnodelog.cpu_freq == _mnodelog.cpu_freq
277
+ assert mnodelog.cpu_guest == _mnodelog.cpu_guest
278
+ assert mnodelog.cpu_guest_nice == _mnodelog.cpu_guest_nice
279
+ assert mnodelog.cpu_idle == _mnodelog.cpu_idle
280
+ assert mnodelog.cpu_interrupts == _mnodelog.cpu_interrupts
281
+ assert mnodelog.cpu_iotwait == _mnodelog.cpu_iotwait
282
+ assert mnodelog.cpu_irq == _mnodelog.cpu_irq
283
+ assert mnodelog.cpu_nice == _mnodelog.cpu_nice
284
+ assert mnodelog.cpu_soft_interrupts == _mnodelog.cpu_soft_interrupts
285
+ assert mnodelog.cpu_softirq == _mnodelog.cpu_softirq
286
+ assert mnodelog.cpu_steal == _mnodelog.cpu_steal
287
+ assert mnodelog.cpu_system == _mnodelog.cpu_system
288
+ assert mnodelog.cpu_user == _mnodelog.cpu_user
289
+
290
+ assert mnodelog.network_bytes_recv == _mnodelog.network_bytes_recv
291
+ assert mnodelog.network_bytes_sent == _mnodelog.network_bytes_sent
292
+ assert (
293
+ mnodelog.network_connection_af_inet
294
+ == _mnodelog.network_connection_af_inet
295
+ )
296
+ assert (
297
+ mnodelog.network_connection_af_inet6
298
+ == _mnodelog.network_connection_af_inet6
299
+ )
300
+ assert (
301
+ mnodelog.network_connection_af_unix
302
+ == _mnodelog.network_connection_af_unix
303
+ )
304
+ assert mnodelog.network_dropin == _mnodelog.network_dropin
305
+ assert mnodelog.network_dropout == _mnodelog.network_dropout
306
+ assert mnodelog.network_errin == _mnodelog.network_errin
307
+ assert mnodelog.network_errout == _mnodelog.network_errout
308
+ assert (
309
+ mnodelog.network_packets_recv == _mnodelog.network_packets_recv
310
+ )
311
+ assert (
312
+ mnodelog.network_packets_sent == _mnodelog.network_packets_sent
313
+ )
314
+
315
+ assert mnodelog.memory_active == _mnodelog.memory_active
316
+ assert mnodelog.memory_available == _mnodelog.memory_available
317
+ assert mnodelog.memory_buffers == _mnodelog.memory_buffers
318
+ assert mnodelog.memory_cached == _mnodelog.memory_cached
319
+ assert mnodelog.memory_free == _mnodelog.memory_free
320
+ assert mnodelog.memory_inactive == _mnodelog.memory_inactive
321
+ assert mnodelog.memory_percent == _mnodelog.memory_percent
322
+ assert mnodelog.memory_shared == _mnodelog.memory_shared
323
+ assert mnodelog.memory_slab == _mnodelog.memory_slab
324
+ assert mnodelog.memory_total == _mnodelog.memory_total
325
+ assert mnodelog.memory_used == _mnodelog.memory_used
326
+
327
+ assert mnodelog.disk_busy_time == _mnodelog.disk_busy_time
328
+ assert mnodelog.disk_read_bytes == _mnodelog.disk_read_bytes
329
+ assert mnodelog.disk_read_count == _mnodelog.disk_read_count
330
+ assert (
331
+ mnodelog.disk_read_merged_count
332
+ == _mnodelog.disk_read_merged_count
333
+ )
334
+ assert mnodelog.disk_read_time == _mnodelog.disk_read_time
335
+ assert mnodelog.disk_write_bytes == _mnodelog.disk_write_bytes
336
+ assert mnodelog.disk_write_count == _mnodelog.disk_write_count
337
+ assert (
338
+ mnodelog.disk_write_merged_count
339
+ == _mnodelog.disk_write_merged_count
340
+ )
341
+ assert mnodelog.disk_write_time == _mnodelog.disk_write_time
342
+
343
+
344
+ def test_mnodelog_queries(N=1000):
345
+ with TemporaryDirectory() as dbpath:
346
+ with zlmdb.Database(dbpath) as db:
347
+ schema = Schema.attach(db)
348
+
349
+ data = {}
350
+
351
+ # insert test data
352
+ #
353
+ with db.begin(write=True) as txn:
354
+ for i in range(N):
355
+ rec = MNodeLog()
356
+ fill_mnodelog(rec)
357
+ key = (rec.timestamp, rec.node_id)
358
+ schema.mnode_logs[txn, key] = rec
359
+
360
+ data[key] = rec
361
+
362
+ # do test scans over inserted data
363
+ #
364
+ with db.begin() as txn:
365
+ # do some record counting queries
366
+ #
367
+ skeys = sorted(data.keys())
368
+ for key in skeys:
369
+ mnodelog = schema.mnode_logs[txn, key]
370
+ assert mnodelog
371
+
372
+ first_key = (np.datetime64(0, "ns"), uuid.UUID(bytes=b"\0" * 16))
373
+ last_key = (
374
+ np.datetime64(2**63 - 1, "ns"),
375
+ uuid.UUID(bytes=b"\xff" * 16),
376
+ )
377
+ cnt = schema.mnode_logs.count_range(
378
+ txn, from_key=first_key, to_key=last_key
379
+ )
380
+ assert cnt == N
381
+
382
+ cnt = schema.mnode_logs.count_range(
383
+ txn, from_key=skeys[0], to_key=skeys[-1]
384
+ )
385
+ assert cnt == N - 1
386
+
387
+ from_key = skeys[0]
388
+ to_key = (skeys[-1][0], uuid.UUID(bytes=b"\xff" * 16))
389
+ cnt = schema.mnode_logs.count_range(
390
+ txn, from_key=from_key, to_key=to_key
391
+ )
392
+ assert cnt == N
393
+
394
+ K = len(skeys) // 2
395
+ cnt = schema.mnode_logs.count_range(
396
+ txn, from_key=skeys[0], to_key=skeys[K]
397
+ )
398
+ assert cnt == N - K
399
+
400
+ K = 10
401
+ from_key = skeys[-K]
402
+ to_key = (skeys[-1][0], uuid.UUID(bytes=b"\xff" * 16))
403
+ cnt = schema.mnode_logs.count_range(
404
+ txn, from_key=from_key, to_key=to_key
405
+ )
406
+ assert cnt == K
407
+
408
+ # do some scanning queries
409
+ #
410
+
411
+ # full scan
412
+ keys1 = []
413
+ for key in schema.mnode_logs.select(
414
+ txn, return_values=False, reverse=False
415
+ ):
416
+ keys1.append(key)
417
+
418
+ assert len(keys1) == N
419
+
420
+ # full reverse scan
421
+ keys2 = []
422
+ for key in schema.mnode_logs.select(
423
+ txn, return_values=False, reverse=True
424
+ ):
425
+ keys2.append(key)
426
+
427
+ assert len(keys2) == N
428
+ assert keys1 == list(reversed(keys2))
429
+
430
+ # scan [from_key, to_key[
431
+ keys1 = []
432
+ for key in schema.mnode_logs.select(
433
+ txn,
434
+ return_values=False,
435
+ from_key=from_key,
436
+ to_key=to_key,
437
+ reverse=False,
438
+ ):
439
+ keys1.append(key)
440
+
441
+ assert len(keys1) == K
442
+
443
+ # reverse scan [from_key, to_key[
444
+ keys2 = []
445
+ for key in schema.mnode_logs.select(
446
+ txn,
447
+ return_values=False,
448
+ from_key=from_key,
449
+ to_key=to_key,
450
+ reverse=True,
451
+ ):
452
+ keys2.append(key)
453
+
454
+ assert len(keys2) == K
455
+ assert keys1 == list(reversed(keys2))
456
+
457
+ K = len(skeys) // 2
458
+ anchor_key = skeys[K]
459
+
460
+ # scan [from_key, ..
461
+ keys1 = []
462
+ for key in schema.mnode_logs.select(
463
+ txn, return_values=False, from_key=anchor_key, reverse=False
464
+ ):
465
+ keys1.append(key)
466
+
467
+ assert len(keys1) == K
468
+ assert skeys[K:] == keys1
469
+
470
+ # reverse scan ..., to_key[
471
+ keys2 = []
472
+ for key in schema.mnode_logs.select(
473
+ txn, return_values=False, to_key=anchor_key, reverse=True
474
+ ):
475
+ keys2.append(key)
476
+
477
+ assert len(keys2) == K
478
+ assert skeys[:K] == list(reversed(keys2))
479
+
480
+ # scan a range with 2 boundaries
481
+ #
482
+ K = 10
483
+ from_key = skeys[K]
484
+ to_key = skeys[-K]
485
+
486
+ _skeys = skeys[K:-K]
487
+ L = len(_skeys)
488
+
489
+ cnt = schema.mnode_logs.count_range(
490
+ txn, from_key=from_key, to_key=to_key
491
+ )
492
+ assert cnt == L
493
+
494
+ # scan [from_key, to_key[
495
+ keys1 = []
496
+ for key in schema.mnode_logs.select(
497
+ txn,
498
+ return_values=False,
499
+ from_key=from_key,
500
+ to_key=to_key,
501
+ reverse=False,
502
+ ):
503
+ keys1.append(key)
504
+
505
+ assert len(keys1) == L
506
+ assert _skeys == keys1
507
+
508
+ # reverse scan [from_key, to_key[
509
+ keys2 = []
510
+ for key in schema.mnode_logs.select(
511
+ txn,
512
+ return_values=False,
513
+ from_key=from_key,
514
+ to_key=to_key,
515
+ reverse=True,
516
+ ):
517
+ keys2.append(key)
518
+
519
+ assert len(keys2) == L
520
+ assert _skeys == list(reversed(keys2))
521
+
522
+
523
+ def _test_mnodelog_bigtable(N, M, K):
524
+ with TemporaryDirectory() as dbpath:
525
+ with zlmdb.Database(dbpath, maxsize=(5 * 2**30)) as db:
526
+ schema = Schema.attach(db)
527
+
528
+ data = {}
529
+ logging.info("")
530
+
531
+ # fill table
532
+ #
533
+ started = time_ns()
534
+ with db.begin(write=True) as txn:
535
+ for i in range(N):
536
+ rec = MNodeLog()
537
+ fill_mnodelog(rec)
538
+ key = (rec.timestamp, rec.node_id)
539
+ schema.mnode_logs[txn, key] = rec
540
+ data[key] = rec
541
+ duration = (time_ns() - started) / 1000000000.0
542
+ rps = int(round(N / duration))
543
+ duration = int(round(duration))
544
+ logging.info(
545
+ "Inserted {} records in {} seconds [{} records/sec]".format(
546
+ N, duration, rps
547
+ )
548
+ )
549
+
550
+ skeys = sorted(data.keys())
551
+
552
+ # random single record selects
553
+ #
554
+ if True:
555
+ started = time_ns()
556
+ with db.begin() as txn:
557
+ for i in range(M):
558
+ key = random.choice(skeys)
559
+ mnodelog = schema.mnode_logs[txn, key]
560
+ assert mnodelog
561
+ duration = (time_ns() - started) / 1000000000.0
562
+ rps = int(round(M / duration))
563
+ duration = int(round(duration))
564
+ logging.info(
565
+ "Selected {} records in {} seconds [{} records/sec]".format(
566
+ M, duration, rps
567
+ )
568
+ )
569
+
570
+ # random range counts
571
+ #
572
+ if True:
573
+ started = time_ns()
574
+ with db.begin() as txn:
575
+ for i in range(K):
576
+ # we select a fixed range of (max) 1000 elements:
577
+ i1 = random.randint(0, len(skeys) - 1)
578
+ i2 = random.randint(i1, min(len(skeys) - 1, i1 + 1000))
579
+ key1 = skeys[i1]
580
+ key2 = skeys[i2]
581
+ cnt = schema.mnode_logs.count_range(
582
+ txn, from_key=key1, to_key=key2
583
+ )
584
+ assert cnt == len(skeys[i1:i2])
585
+ duration = (time_ns() - started) / 1000000000.0
586
+ rps = int(round(K / duration))
587
+ duration = int(round(duration))
588
+ logging.info(
589
+ "Performed {} range counts in {} seconds [{} queries/sec]".format(
590
+ K, duration, rps
591
+ )
592
+ )
593
+
594
+
595
+ def test_mnodelog_bigtable_size10k():
596
+ _test_mnodelog_bigtable(N=10000, M=500000, K=10000)
597
+
598
+
599
+ def test_mnodelog_bigtable_size20k():
600
+ _test_mnodelog_bigtable(N=20000, M=1000000, K=20000)
601
+
602
+
603
+ def test_mnodelog_bigtable_size40k():
604
+ _test_mnodelog_bigtable(N=40000, M=2000000, K=40000)
605
+
606
+
607
+ @pytest.mark.skipif(QUICK, reason="skipped in run-mode QUICK")
608
+ def test_mnodelog_bigtable_size80k():
609
+ _test_mnodelog_bigtable(N=80000, M=4000000, K=80000)
610
+
611
+
612
+ @pytest.mark.skipif(QUICK, reason="skipped in run-mode QUICK")
613
+ def test_mnodelog_bigtable_size160k():
614
+ _test_mnodelog_bigtable(N=160000, M=8000000, K=160000)
615
+
616
+
617
+ @pytest.mark.skipif(QUICK, reason="skipped in run-mode QUICK")
618
+ def test_mnodelog_bigtable_size320k():
619
+ _test_mnodelog_bigtable(N=320000, M=16000000, K=320000)