zlmdb 25.10.1__cp312-cp312-win_amd64.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.

Potentially problematic release.


This version of zlmdb might be problematic. Click here for more details.

Files changed (86) hide show
  1. flatbuffers/__init__.py +19 -0
  2. flatbuffers/_version.py +17 -0
  3. flatbuffers/builder.py +776 -0
  4. flatbuffers/compat.py +86 -0
  5. flatbuffers/encode.py +42 -0
  6. flatbuffers/flexbuffers.py +1527 -0
  7. flatbuffers/number_types.py +181 -0
  8. flatbuffers/packer.py +42 -0
  9. flatbuffers/reflection/AdvancedFeatures.py +10 -0
  10. flatbuffers/reflection/BaseType.py +24 -0
  11. flatbuffers/reflection/Enum.py +169 -0
  12. flatbuffers/reflection/EnumVal.py +96 -0
  13. flatbuffers/reflection/Field.py +208 -0
  14. flatbuffers/reflection/KeyValue.py +56 -0
  15. flatbuffers/reflection/Object.py +175 -0
  16. flatbuffers/reflection/RPCCall.py +131 -0
  17. flatbuffers/reflection/Schema.py +206 -0
  18. flatbuffers/reflection/SchemaFile.py +77 -0
  19. flatbuffers/reflection/Service.py +145 -0
  20. flatbuffers/reflection/Type.py +98 -0
  21. flatbuffers/reflection/__init__.py +0 -0
  22. flatbuffers/table.py +129 -0
  23. flatbuffers/util.py +43 -0
  24. zlmdb/__init__.py +312 -0
  25. zlmdb/_database.py +990 -0
  26. zlmdb/_errors.py +31 -0
  27. zlmdb/_meta.py +27 -0
  28. zlmdb/_pmap.py +1667 -0
  29. zlmdb/_schema.py +137 -0
  30. zlmdb/_transaction.py +181 -0
  31. zlmdb/_types.py +1596 -0
  32. zlmdb/_version.py +27 -0
  33. zlmdb/cli.py +41 -0
  34. zlmdb/flatbuffers/__init__.py +5 -0
  35. zlmdb/flatbuffers/reflection/AdvancedFeatures.py +10 -0
  36. zlmdb/flatbuffers/reflection/BaseType.py +25 -0
  37. zlmdb/flatbuffers/reflection/Enum.py +252 -0
  38. zlmdb/flatbuffers/reflection/EnumVal.py +144 -0
  39. zlmdb/flatbuffers/reflection/Field.py +325 -0
  40. zlmdb/flatbuffers/reflection/KeyValue.py +84 -0
  41. zlmdb/flatbuffers/reflection/Object.py +260 -0
  42. zlmdb/flatbuffers/reflection/RPCCall.py +195 -0
  43. zlmdb/flatbuffers/reflection/Schema.py +301 -0
  44. zlmdb/flatbuffers/reflection/SchemaFile.py +112 -0
  45. zlmdb/flatbuffers/reflection/Service.py +213 -0
  46. zlmdb/flatbuffers/reflection/Type.py +148 -0
  47. zlmdb/flatbuffers/reflection/__init__.py +0 -0
  48. zlmdb/flatbuffers/reflection.fbs +152 -0
  49. zlmdb/lmdb/__init__.py +37 -0
  50. zlmdb/lmdb/__main__.py +25 -0
  51. zlmdb/lmdb/_config.py +10 -0
  52. zlmdb/lmdb/cffi.py +2606 -0
  53. zlmdb/lmdb/tool.py +670 -0
  54. zlmdb/tests/lmdb/__init__.py +0 -0
  55. zlmdb/tests/lmdb/address_book.py +287 -0
  56. zlmdb/tests/lmdb/crash_test.py +339 -0
  57. zlmdb/tests/lmdb/cursor_test.py +333 -0
  58. zlmdb/tests/lmdb/env_test.py +919 -0
  59. zlmdb/tests/lmdb/getmulti_test.py +92 -0
  60. zlmdb/tests/lmdb/iteration_test.py +258 -0
  61. zlmdb/tests/lmdb/package_test.py +70 -0
  62. zlmdb/tests/lmdb/test_lmdb.py +188 -0
  63. zlmdb/tests/lmdb/testlib.py +185 -0
  64. zlmdb/tests/lmdb/tool_test.py +60 -0
  65. zlmdb/tests/lmdb/txn_test.py +575 -0
  66. zlmdb/tests/orm/MNodeLog.py +853 -0
  67. zlmdb/tests/orm/__init__.py +0 -0
  68. zlmdb/tests/orm/_schema_fbs.py +215 -0
  69. zlmdb/tests/orm/_schema_mnode_log.py +1201 -0
  70. zlmdb/tests/orm/_schema_py2.py +250 -0
  71. zlmdb/tests/orm/_schema_py3.py +307 -0
  72. zlmdb/tests/orm/_test_flatbuffers.py +144 -0
  73. zlmdb/tests/orm/_test_serialization.py +144 -0
  74. zlmdb/tests/orm/test_basic.py +217 -0
  75. zlmdb/tests/orm/test_etcd.py +275 -0
  76. zlmdb/tests/orm/test_pmap_indexes.py +466 -0
  77. zlmdb/tests/orm/test_pmap_types.py +90 -0
  78. zlmdb/tests/orm/test_pmaps.py +295 -0
  79. zlmdb/tests/orm/test_select.py +619 -0
  80. zlmdb-25.10.1.dist-info/METADATA +264 -0
  81. zlmdb-25.10.1.dist-info/RECORD +86 -0
  82. zlmdb-25.10.1.dist-info/WHEEL +5 -0
  83. zlmdb-25.10.1.dist-info/entry_points.txt +2 -0
  84. zlmdb-25.10.1.dist-info/licenses/LICENSE +137 -0
  85. zlmdb-25.10.1.dist-info/licenses/NOTICE +41 -0
  86. zlmdb-25.10.1.dist-info/top_level.txt +2 -0
zlmdb/lmdb/tool.py ADDED
@@ -0,0 +1,670 @@
1
+ #
2
+ # Copyright 2013 The py-lmdb authors, all rights reserved.
3
+ #
4
+ # Redistribution and use in source and binary forms, with or without
5
+ # modification, are permitted only as authorized by the OpenLDAP
6
+ # Public License.
7
+ #
8
+ # A copy of this license is available in the file LICENSE in the
9
+ # top-level directory of the distribution or, alternatively, at
10
+ # <http://www.OpenLDAP.org/license.html>.
11
+ #
12
+ # OpenLDAP is a registered trademark of the OpenLDAP Foundation.
13
+ #
14
+ # Individual files and/or contributed packages may be copyright by
15
+ # other parties and/or subject to additional restrictions.
16
+ #
17
+ # This work also contains materials derived from public sources.
18
+ #
19
+ # Additional information about OpenLDAP can be obtained at
20
+ # <http://www.openldap.org/>.
21
+ #
22
+
23
+ """
24
+ Basic tools for working with LMDB.
25
+
26
+ copy: Consistent high speed backup an environment.
27
+ %prog copy -e source.lmdb target.lmdb
28
+
29
+ copyfd: Consistent high speed backup an environment to stdout.
30
+ %prog copyfd -e source.lmdb > target.lmdb/data.mdb
31
+
32
+ drop: Delete one or more sub-databases.
33
+ %prog drop db1
34
+
35
+ dump: Dump one or more databases to disk in 'cdbmake' format.
36
+ Usage: dump [db1=file1.cdbmake db2=file2.cdbmake]
37
+
38
+ If no databases are given, dumps the main database to 'main.cdbmake'.
39
+
40
+ edit: Add/delete/replace values from a database.
41
+ %prog edit --set key=value --set-file key=/path \\
42
+ --add key=value --add-file key=/path/to/file \\
43
+ --delete key
44
+
45
+ get: Read one or more values from a database.
46
+ %prog get [<key1> [<keyN> [..]]]
47
+
48
+ readers: Display readers in the lock table
49
+ %prog readers -e /path/to/db [-c]
50
+
51
+ If -c is specified, clear stale readers.
52
+
53
+ restore: Read one or more database from disk in 'cdbmake' format.
54
+ %prog restore db1=file1.cdbmake db2=file2.cdbmake
55
+
56
+ The special db name ":main:" may be used to indicate the main DB.
57
+
58
+ rewrite: Re-create an environment using MDB_APPEND
59
+ %prog rewrite -e src.lmdb -E dst.lmdb [<db1> [<dbN> ..]]
60
+
61
+ If no databases are given, rewrites only the main database.
62
+
63
+ shell: Open interactive console with ENV set to the open environment.
64
+
65
+ stat: Print environment statistics.
66
+
67
+ warm: Read environment into page cache sequentially.
68
+
69
+ watch: Show live environment statistics
70
+ """
71
+
72
+ from __future__ import absolute_import
73
+ from __future__ import with_statement
74
+ import array
75
+ import collections
76
+ import csv
77
+ import functools
78
+ import optparse
79
+ import os
80
+ import pprint
81
+ import signal
82
+ import string
83
+ import struct
84
+ import sys
85
+ import time
86
+
87
+ # Python3.x bikeshedded trechery.
88
+ try:
89
+ from io import BytesIO as StringIO
90
+ except ImportError:
91
+ try:
92
+ from cStringIO import StringIO # type: ignore
93
+ except ImportError:
94
+ from StringIO import StringIO # type: ignore
95
+
96
+ import zlmdb.lmdb as lmdb
97
+
98
+
99
+ BUF_SIZE = 10485760
100
+ ENV = None
101
+ DB = None
102
+
103
+ # How strings get encoded to and decoded from DB
104
+ ENCODING = "utf-8"
105
+
106
+
107
+ def _to_bytes(s):
108
+ """Given either a Python 2.x or 3.x str, return either a str (Python 2.x)
109
+ or a bytes instance (Python 3.x)."""
110
+ return globals().get("unicode", str)(s).encode(ENCODING)
111
+
112
+
113
+ def isprint(c):
114
+ """Return ``True`` if the character `c` can be printed visibly and without
115
+ adversely affecting printing position (e.g. newline)."""
116
+ return c in string.printable and ord(c) > 16
117
+
118
+
119
+ def xxd(s):
120
+ """Return a vaguely /usr/bin/xxd formatted representation of the bytestring
121
+ `s`."""
122
+ sio = StringIO()
123
+ pr = _to_bytes("")
124
+ for idx, ch in enumerate(s):
125
+ if sys.version_info[0] >= 3:
126
+ ch = chr(ch)
127
+ if not (idx % 16):
128
+ if idx:
129
+ sio.write(_to_bytes(" "))
130
+ sio.write(pr)
131
+ sio.write(_to_bytes("\n"))
132
+ sio.write(_to_bytes("%07x:" % idx))
133
+ pr = _to_bytes("")
134
+ if not (idx % 2):
135
+ sio.write(_to_bytes(" "))
136
+ sio.write(_to_bytes("%02x" % (ord(ch),)))
137
+ pr += _to_bytes(ch) if isprint(ch) else _to_bytes(".")
138
+
139
+ if idx % 16:
140
+ need = 15 - (idx % 16)
141
+ # fill remainder of last line.
142
+ sio.write(_to_bytes(" ") * need)
143
+ sio.write(_to_bytes(" ") * (need // 2))
144
+ sio.write(_to_bytes(" "))
145
+ sio.write(pr)
146
+
147
+ sio.write(_to_bytes("\n"))
148
+ return sio.getvalue().decode(ENCODING)
149
+
150
+
151
+ def make_parser():
152
+ parser = optparse.OptionParser()
153
+ parser.prog = "python -mlmdb"
154
+ parser.usage = "%prog [options] <command>\n" + __doc__.rstrip()
155
+ parser.add_option("-e", "--env", help="Environment file to open")
156
+ parser.add_option("-d", "--db", help="Database to open (default: main)")
157
+ parser.add_option("-r", "--read", help="Open environment read-only")
158
+ parser.add_option(
159
+ "-S",
160
+ "--map_size",
161
+ type="int",
162
+ default="10",
163
+ help="Map size in megabytes (default: 10)",
164
+ )
165
+ parser.add_option(
166
+ "-s",
167
+ "--use-single-file",
168
+ action="store_true",
169
+ help="The database was created as a single file and not a subdirectory",
170
+ )
171
+ # FIXME: implement --all
172
+ # parser.add_option('-a', '--all', action='store_true',
173
+ # help='Make "dump" dump all databases')
174
+ parser.add_option("-E", "--target_env", help='Target environment file for "dumpfd"')
175
+ parser.add_option(
176
+ "-x", "--xxd", action="store_true", help="Print values in xxd format"
177
+ )
178
+ parser.add_option(
179
+ "-M",
180
+ "--max-dbs",
181
+ type="int",
182
+ default=128,
183
+ help="Maximum open DBs (default: 128)",
184
+ )
185
+ parser.add_option(
186
+ "--out-fd", type="int", default=1, help='"copyfd" command target fd'
187
+ )
188
+ group = parser.add_option_group('Options for "copy" command')
189
+ group.add_option(
190
+ "--compact",
191
+ action="store_true",
192
+ default=False,
193
+ help="Perform compaction while copying.",
194
+ )
195
+ group = parser.add_option_group('Options for "edit" command')
196
+ group.add_option("--set", action="append", help="List of key=value pairs to set.")
197
+ group.add_option(
198
+ "--set-file", action="append", help="List of key pairs to read from files."
199
+ )
200
+ group.add_option("--add", action="append", help="List of key=value pairs to add.")
201
+ group.add_option(
202
+ "--add-file", action="append", help="List of key pairs to read from files."
203
+ )
204
+ group.add_option(
205
+ "--delete", action="append", help="List of key=value pairs to delete."
206
+ )
207
+ group = parser.add_option_group('Options for "readers" command')
208
+ group.add_option(
209
+ "-c", "--clean", action="store_true", help="Clean stale readers? (default: no)"
210
+ )
211
+ group = parser.add_option_group('Options for "watch" command')
212
+ group.add_option(
213
+ "--csv", action="store_true", help="Generate CSV instead of terminal output."
214
+ )
215
+ group.add_option(
216
+ "--interval", type="int", default=1, help="Interval size (default: 1sec)"
217
+ )
218
+ group.add_option(
219
+ "--window", type="int", default=10, help="Average window size (default: 10)"
220
+ )
221
+ return parser
222
+
223
+
224
+ def die(fmt, *args):
225
+ if args:
226
+ fmt %= args
227
+ sys.stderr.write("lmdb.tool: %s\n" % (fmt,))
228
+ raise SystemExit(1)
229
+
230
+
231
+ def dump_cursor_to_fp(cursor, fp):
232
+ for key, value in cursor:
233
+ fp.write(_to_bytes("+%d,%d:" % (len(key), len(value))))
234
+ fp.write(key)
235
+ fp.write(_to_bytes("->"))
236
+ fp.write(value)
237
+ fp.write(_to_bytes("\n"))
238
+ fp.write(_to_bytes("\n"))
239
+
240
+
241
+ def db_map_from_args(args):
242
+ db_map = {}
243
+
244
+ for arg in args:
245
+ dbname, sep, path = arg.partition("=")
246
+ if not sep:
247
+ die('DB specification missing "=": %r', arg)
248
+
249
+ if dbname == ":main:":
250
+ dbname = None
251
+ if dbname in db_map:
252
+ die("DB specified twice: %r", arg)
253
+ db_map[dbname] = (ENV.open_db(_to_bytes(dbname) if dbname else None), path)
254
+
255
+ if not db_map:
256
+ db_map[":main:"] = (ENV.open_db(None), "main.cdbmake")
257
+ return db_map
258
+
259
+
260
+ def cmd_copy(opts, args):
261
+ if len(args) != 1:
262
+ die("Please specify output directory (see --help)")
263
+
264
+ output_dir = args[0]
265
+ if os.path.exists(output_dir):
266
+ die("Output directory %r already exists.", output_dir)
267
+
268
+ os.makedirs(output_dir, int("0755", 8))
269
+ print("Running copy to %r...." % (output_dir,))
270
+ ENV.copy(output_dir, compact=opts.compact)
271
+
272
+
273
+ def cmd_copyfd(opts, args):
274
+ if args:
275
+ die('"copyfd" command takes no arguments (see --help)')
276
+
277
+ try:
278
+ os.fdopen(opts.out_fd, "w", 0)
279
+ except OSError:
280
+ e = sys.exc_info()[1]
281
+ die("Bad --out-fd %d: %s", opts.out_fd, e)
282
+
283
+ ENV.copyfd(opts.out_fd)
284
+
285
+
286
+ def cmd_dump(opts, args):
287
+ db_map = db_map_from_args(args)
288
+ with ENV.begin(buffers=True) as txn:
289
+ for dbname, (db, path) in db_map.items():
290
+ with open(path, "wb", BUF_SIZE) as fp:
291
+ print("Dumping to %r..." % (path,))
292
+ cursor = txn.cursor(db=db)
293
+ dump_cursor_to_fp(cursor, fp)
294
+
295
+
296
+ def restore_cursor_from_fp(txn, fp, db):
297
+ read = fp.read
298
+ read1 = functools.partial(read, 1)
299
+ read_until = lambda sep: b"".join(iter(read1, sep)) # NOQA: E731
300
+
301
+ rec_nr = 0
302
+
303
+ while True:
304
+ rec_nr += 1
305
+ plus = read(1)
306
+ if plus == b"\n":
307
+ break
308
+ elif plus != b"+":
309
+ die("bad or missing plus, line/record #%d", rec_nr)
310
+
311
+ try:
312
+ klen = int(read_until(b","), 10)
313
+ dlen = int(read_until(b":"), 10)
314
+ except ValueError:
315
+ die("bad or missing length, line/record #%d", rec_nr)
316
+
317
+ key = read(klen)
318
+ if read(2) != b"->":
319
+ die("bad or missing separator, line/record #%d", rec_nr)
320
+
321
+ data = read(dlen)
322
+ if (len(key) + len(data)) != (klen + dlen):
323
+ die("short key or data, line/record #%d", rec_nr)
324
+
325
+ if read(1) != b"\n":
326
+ die("bad line ending, line/record #%d", rec_nr)
327
+
328
+ txn.put(key, data, db=db)
329
+
330
+ return rec_nr
331
+
332
+
333
+ def cmd_drop(opts, args):
334
+ if not args:
335
+ die("Must specify at least one sub-database (see --help)")
336
+
337
+ dbs = map(ENV.open_db, (map(_to_bytes, args)))
338
+ for idx, db in enumerate(dbs):
339
+ name = args[idx]
340
+ if name == ":main:":
341
+ die("Cannot drop main DB")
342
+ print("Dropping DB %r..." % (name,))
343
+ with ENV.begin(write=True) as txn:
344
+ txn.drop(db)
345
+
346
+
347
+ def cmd_readers(opts, args):
348
+ if opts.clean:
349
+ print("Cleaned %d stale entries." % (ENV.reader_check(),))
350
+ print(ENV.readers())
351
+
352
+
353
+ def cmd_restore(opts, args):
354
+ db_map = db_map_from_args(args)
355
+ with ENV.begin(buffers=True, write=True) as txn:
356
+ for dbname, (db, path) in db_map.items():
357
+ with open(path, "rb", BUF_SIZE) as fp:
358
+ print("Restoring from %r..." % (path,))
359
+ count = restore_cursor_from_fp(txn, fp, db)
360
+ print("Loaded %d keys from %r" % (count, path))
361
+
362
+
363
+ def delta(hst):
364
+ return [(hst[i] - hst[i - 1]) for i in range(1, len(hst))]
365
+
366
+
367
+ SYS_BLOCK = "/sys/block"
368
+
369
+
370
+ def _find_diskstat(path):
371
+ if not os.path.exists(SYS_BLOCK):
372
+ return
373
+ st = os.stat(path)
374
+ devs = "%s:%s" % (st.st_dev >> 8, st.st_dev & 0xFF)
375
+
376
+ def maybe(rootpath):
377
+ dpath = os.path.join(rootpath, "dev")
378
+ if os.path.exists(dpath):
379
+ with open(dpath) as fp:
380
+ if fp.read().strip() == devs:
381
+ return os.path.join(rootpath, "stat")
382
+
383
+ for name in os.listdir(SYS_BLOCK):
384
+ basepath = os.path.join(SYS_BLOCK, name)
385
+ statpath = maybe(basepath)
386
+ if statpath:
387
+ return statpath
388
+ for name in os.listdir(basepath):
389
+ base2path = os.path.join(basepath, name)
390
+ statpath = maybe(base2path)
391
+ if statpath:
392
+ return statpath
393
+
394
+
395
+ class DiskStatter(object):
396
+ FIELDS = (
397
+ "reads",
398
+ "reads_merged",
399
+ "sectors_read",
400
+ "read_ms",
401
+ "writes",
402
+ "writes_merged",
403
+ "sectors_written",
404
+ "write_ms",
405
+ "io_count",
406
+ "io_ms",
407
+ "total_ms",
408
+ )
409
+
410
+ def __init__(self, path):
411
+ self.fp = open(path)
412
+ self.refresh()
413
+
414
+ def refresh(self):
415
+ self.fp.seek(0)
416
+ vars(self).update(
417
+ (self.FIELDS[i], int(s)) for i, s in enumerate(self.fp.read().split())
418
+ )
419
+
420
+
421
+ def cmd_watch(opts, args):
422
+ info = None
423
+ stat = None
424
+
425
+ def window(func):
426
+ history = collections.deque()
427
+
428
+ def windowfunc():
429
+ history.append(func())
430
+ if len(history) > opts.window:
431
+ history.popleft()
432
+ if len(history) <= 1:
433
+ return 0
434
+ n = sum(delta(history)) / float(len(history) - 1)
435
+ return n / opts.interval
436
+
437
+ return windowfunc
438
+
439
+ envmb = lambda: (info["last_pgno"] * stat["psize"]) / 1048576.0 # NOQA
440
+
441
+ cols = [
442
+ ("%d", "Depth", lambda: stat["depth"]),
443
+ ("%d", "Branch", lambda: stat["branch_pages"]),
444
+ ("%d", "Leaf", lambda: stat["leaf_pages"]),
445
+ ("%+d", "Leaf/s", window(lambda: stat["leaf_pages"])),
446
+ ("%d", "Oflow", lambda: stat["overflow_pages"]),
447
+ ("%+d", "Oflow/s", window(lambda: stat["overflow_pages"])),
448
+ ("%d", "Recs", lambda: stat["entries"]),
449
+ ("%+d", "Recs/s", window(lambda: stat["entries"])),
450
+ ("%d", "Rdrs", lambda: info["num_readers"]),
451
+ ("%.2f", "EnvMb", envmb),
452
+ ("%+.2f", "EnvMb/s", window(envmb)),
453
+ ("%d", "Txs", lambda: info["last_txnid"]),
454
+ ("%+.2f", "Txs/s", window(lambda: info["last_txnid"])),
455
+ ]
456
+
457
+ statter = None
458
+ statpath = _find_diskstat(ENV.path())
459
+ if statpath:
460
+ statter = DiskStatter(statpath)
461
+ cols += [
462
+ ("%+d", "SctRd/s", window(lambda: statter.sectors_read)),
463
+ ("%+d", "SctWr/s", window(lambda: statter.sectors_written)),
464
+ ]
465
+
466
+ term_width = 0
467
+ widths = [len(head) for _, head, _ in cols]
468
+
469
+ if opts.csv:
470
+ writer = csv.writer(sys.stdout, quoting=csv.QUOTE_ALL)
471
+ writer.writerow([head for _, head, _ in cols])
472
+
473
+ cnt = 0
474
+ try:
475
+ while True:
476
+ stat = ENV.stat()
477
+ info = ENV.info()
478
+ if statter:
479
+ statter.refresh()
480
+
481
+ vals = []
482
+ for i, (fmt, head, func) in enumerate(cols):
483
+ val = fmt % func()
484
+ vals.append(val)
485
+ widths[i] = max(widths[i], len(val))
486
+
487
+ if opts.csv:
488
+ writer.writerow(vals)
489
+ else:
490
+ if term_width != _TERM_WIDTH or not (cnt % (_TERM_HEIGHT - 2)):
491
+ for i, (fmt, head, func) in enumerate(cols):
492
+ sys.stdout.write(head.rjust(widths[i] + 1))
493
+ sys.stdout.write("\n")
494
+ term_width = _TERM_WIDTH
495
+ for i, val in enumerate(vals):
496
+ sys.stdout.write(val.rjust(widths[i] + 1))
497
+ sys.stdout.write("\n")
498
+
499
+ time.sleep(opts.interval)
500
+ cnt += 1
501
+ except KeyboardInterrupt:
502
+ pass
503
+
504
+
505
+ def cmd_warm(opts, args):
506
+ stat = ENV.stat()
507
+ info = ENV.info()
508
+
509
+ bufsize = 32768
510
+ last_offset = stat["psize"] * info["last_pgno"]
511
+ buf = array.array("B", _to_bytes("\x00" * bufsize))
512
+ t0 = time.time()
513
+
514
+ if opts.use_single_file:
515
+ fp = open(opts.env, "rb", bufsize)
516
+ else:
517
+ fp = open(opts.env + "/data.mdb", "rb", bufsize)
518
+ while fp.tell() < last_offset:
519
+ fp.readinto(buf)
520
+ print(
521
+ "Warmed %.2fmb in %dms" % (last_offset / 1048576.0, 1000 * (time.time() - t0))
522
+ )
523
+
524
+
525
+ def cmd_rewrite(opts, args):
526
+ if not opts.target_env:
527
+ die("Must specify target environment path with -E")
528
+
529
+ src_info = ENV.info()
530
+ target_env = lmdb.open(
531
+ opts.target_env,
532
+ map_size=src_info["map_size"] * 2,
533
+ max_dbs=opts.max_dbs,
534
+ sync=False,
535
+ writemap=True,
536
+ map_async=True,
537
+ metasync=False,
538
+ )
539
+
540
+ dbs = []
541
+ for arg in args:
542
+ name = None if arg == ":main:" else arg
543
+ src_db = ENV.open_db(_to_bytes(name))
544
+ dst_db = target_env.open_db(_to_bytes(name))
545
+ dbs.append((arg, src_db, dst_db))
546
+
547
+ if not dbs:
548
+ dbs.append((":main:", ENV.open_db(None), target_env.open_db(None)))
549
+
550
+ for name, src_db, dst_db in dbs:
551
+ print("Writing %r..." % (name,))
552
+ with target_env.begin(db=dst_db, write=True) as wtxn:
553
+ with ENV.begin(db=src_db, buffers=True) as rtxn:
554
+ for key, value in rtxn.cursor():
555
+ wtxn.put(key, value, append=True)
556
+
557
+ print("Syncing..")
558
+ target_env.sync(True)
559
+
560
+
561
+ def cmd_get(opts, args):
562
+ print_header = len(args) > 1
563
+
564
+ with ENV.begin(buffers=True, db=DB) as txn:
565
+ for arg in args:
566
+ value = txn.get(_to_bytes(arg))
567
+ if value is None:
568
+ print("%r: missing" % (arg,))
569
+ continue
570
+ if print_header:
571
+ print("%r:" % (arg,))
572
+ if opts.xxd:
573
+ print(xxd(value))
574
+ else:
575
+ print(bytes(value))
576
+
577
+
578
+ def cmd_edit(opts, args):
579
+ if args:
580
+ die("Edit command only takes options, not arguments (see --help)")
581
+
582
+ with ENV.begin(write=True) as txn:
583
+ cursor = txn.cursor(db=DB)
584
+ for elem in opts.add or []:
585
+ key, _, value = _to_bytes(elem).partition(_to_bytes("="))
586
+ cursor.put(key, value, overwrite=False)
587
+
588
+ for elem in opts.set or []:
589
+ key, _, value = _to_bytes(elem).partition(_to_bytes("="))
590
+ cursor.put(key, value)
591
+
592
+ for key in opts.delete or []:
593
+ txn.delete(_to_bytes(key), db=DB)
594
+
595
+ for elem in opts.add_file or []:
596
+ key, _, path = _to_bytes(elem).partition(_to_bytes("="))
597
+ with open(path, "rb") as fp:
598
+ cursor.put(key, fp.read(), overwrite=False)
599
+
600
+ for elem in opts.set_file or []:
601
+ key, _, path = _to_bytes(elem).partition(_to_bytes("="))
602
+ with open(path, "rb") as fp:
603
+ cursor.put(key, fp.read())
604
+
605
+
606
+ def cmd_shell(opts, args):
607
+ import code
608
+ import readline # NOQA
609
+
610
+ code.InteractiveConsole(globals()).interact()
611
+
612
+
613
+ def cmd_stat(opts, args):
614
+ pprint.pprint(ENV.stat())
615
+ pprint.pprint(ENV.info())
616
+
617
+
618
+ def _get_term_width(default=(80, 25)):
619
+ try:
620
+ import fcntl # No fcntl on win32
621
+ import termios # No termios on win32
622
+
623
+ s = fcntl.ioctl(sys.stdout.fileno(), termios.TIOCGWINSZ, "1234")
624
+ height, width = struct.unpack("hh", s)
625
+ return width, height
626
+ except Exception:
627
+ return default
628
+
629
+
630
+ def _on_sigwinch(*args):
631
+ global _TERM_WIDTH, _TERM_HEIGHT
632
+ _TERM_WIDTH, _TERM_HEIGHT = _get_term_width()
633
+
634
+
635
+ def main(argv=None):
636
+ parser = make_parser()
637
+ opts, args = parser.parse_args(argv)
638
+
639
+ if not args:
640
+ die("Please specify a command (see --help)")
641
+ if not opts.env:
642
+ die("Please specify environment (--env)")
643
+
644
+ global ENV
645
+ ENV = lmdb.open(
646
+ opts.env,
647
+ map_size=opts.map_size * 1048576,
648
+ subdir=not opts.use_single_file,
649
+ max_dbs=opts.max_dbs,
650
+ create=False,
651
+ readonly=opts.read == "READ",
652
+ )
653
+
654
+ if opts.db:
655
+ global DB
656
+ DB = ENV.open_db(_to_bytes(opts.db))
657
+
658
+ if hasattr(signal, "SIGWINCH"): # Disable on win32.
659
+ signal.signal(signal.SIGWINCH, _on_sigwinch)
660
+ _on_sigwinch()
661
+
662
+ func = globals().get("cmd_" + args[0])
663
+ if not func:
664
+ die("No such command: %r" % (args[0],))
665
+
666
+ func(opts, args[1:])
667
+
668
+
669
+ if __name__ == "__main__":
670
+ main(sys.argv[1:])
File without changes