dhruva 0.6.0__tar.gz

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 (212) hide show
  1. dhruva-0.6.0/.archive/old_durus_package/durus/__init__.py +84 -0
  2. dhruva-0.6.0/.archive/old_durus_package/durus/__main__.py +441 -0
  3. dhruva-0.6.0/.archive/old_durus_package/durus/backup/__init__.py +32 -0
  4. dhruva-0.6.0/.archive/old_durus_package/durus/backup/catalog.py +271 -0
  5. dhruva-0.6.0/.archive/old_durus_package/durus/backup/cli.py +525 -0
  6. dhruva-0.6.0/.archive/old_durus_package/durus/backup/manager.py +440 -0
  7. dhruva-0.6.0/.archive/old_durus_package/durus/backup/restore.py +336 -0
  8. dhruva-0.6.0/.archive/old_durus_package/durus/backup/scheduler.py +368 -0
  9. dhruva-0.6.0/.archive/old_durus_package/durus/backup/storage.py +386 -0
  10. dhruva-0.6.0/.archive/old_durus_package/durus/backup/verification.py +436 -0
  11. dhruva-0.6.0/.archive/old_durus_package/durus/btree.py +9 -0
  12. dhruva-0.6.0/.archive/old_durus_package/durus/collections/__init__.py +21 -0
  13. dhruva-0.6.0/.archive/old_durus_package/durus/collections/btree.py +598 -0
  14. dhruva-0.6.0/.archive/old_durus_package/durus/collections/dict.py +131 -0
  15. dhruva-0.6.0/.archive/old_durus_package/durus/collections/list.py +150 -0
  16. dhruva-0.6.0/.archive/old_durus_package/durus/collections/set.py +189 -0
  17. dhruva-0.6.0/.archive/old_durus_package/durus/config/__init__.py +39 -0
  18. dhruva-0.6.0/.archive/old_durus_package/durus/config/defaults.py +177 -0
  19. dhruva-0.6.0/.archive/old_durus_package/durus/config/loader.py +355 -0
  20. dhruva-0.6.0/.archive/old_durus_package/durus/config/security.py +451 -0
  21. dhruva-0.6.0/.archive/old_durus_package/durus/connection.py +9 -0
  22. dhruva-0.6.0/.archive/old_durus_package/durus/core/__init__.py +20 -0
  23. dhruva-0.6.0/.archive/old_durus_package/durus/core/connection.py +530 -0
  24. dhruva-0.6.0/.archive/old_durus_package/durus/core/persistent.py +290 -0
  25. dhruva-0.6.0/.archive/old_durus_package/durus/error.py +59 -0
  26. dhruva-0.6.0/.archive/old_durus_package/durus/file.py +148 -0
  27. dhruva-0.6.0/.archive/old_durus_package/durus/file_storage.py +9 -0
  28. dhruva-0.6.0/.archive/old_durus_package/durus/file_storage2.py +360 -0
  29. dhruva-0.6.0/.archive/old_durus_package/durus/logger.py +37 -0
  30. dhruva-0.6.0/.archive/old_durus_package/durus/logging/__init__.py +29 -0
  31. dhruva-0.6.0/.archive/old_durus_package/durus/logging/logger.py +233 -0
  32. dhruva-0.6.0/.archive/old_durus_package/durus/mcp/__init__.py +33 -0
  33. dhruva-0.6.0/.archive/old_durus_package/durus/mcp/auth.py +863 -0
  34. dhruva-0.6.0/.archive/old_durus_package/durus/mcp/middleware.py +423 -0
  35. dhruva-0.6.0/.archive/old_durus_package/durus/mcp/oneiric_server.py +483 -0
  36. dhruva-0.6.0/.archive/old_durus_package/durus/mcp/server.py +543 -0
  37. dhruva-0.6.0/.archive/old_durus_package/durus/persistent.py +9 -0
  38. dhruva-0.6.0/.archive/old_durus_package/durus/persistent_dict.py +11 -0
  39. dhruva-0.6.0/.archive/old_durus_package/durus/persistent_list.py +9 -0
  40. dhruva-0.6.0/.archive/old_durus_package/durus/persistent_set.py +9 -0
  41. dhruva-0.6.0/.archive/old_durus_package/durus/security/__init__.py +26 -0
  42. dhruva-0.6.0/.archive/old_durus_package/durus/security/oneiric_secrets.py +432 -0
  43. dhruva-0.6.0/.archive/old_durus_package/durus/serialize/__init__.py +53 -0
  44. dhruva-0.6.0/.archive/old_durus_package/durus/serialize/adapter.py +118 -0
  45. dhruva-0.6.0/.archive/old_durus_package/durus/serialize/base.py +92 -0
  46. dhruva-0.6.0/.archive/old_durus_package/durus/serialize/dill.py +125 -0
  47. dhruva-0.6.0/.archive/old_durus_package/durus/serialize/factory.py +79 -0
  48. dhruva-0.6.0/.archive/old_durus_package/durus/serialize/msgspec.py +124 -0
  49. dhruva-0.6.0/.archive/old_durus_package/durus/serialize/pickle.py +87 -0
  50. dhruva-0.6.0/.archive/old_durus_package/durus/serialize_legacy.py +242 -0
  51. dhruva-0.6.0/.archive/old_durus_package/durus/server/__init__.py +14 -0
  52. dhruva-0.6.0/.archive/old_durus_package/durus/server/server.py +526 -0
  53. dhruva-0.6.0/.archive/old_durus_package/durus/server/socket.py +66 -0
  54. dhruva-0.6.0/.archive/old_durus_package/durus/shelf.py +442 -0
  55. dhruva-0.6.0/.archive/old_durus_package/durus/storage/__init__.py +25 -0
  56. dhruva-0.6.0/.archive/old_durus_package/durus/storage/base.py +196 -0
  57. dhruva-0.6.0/.archive/old_durus_package/durus/storage/client.py +154 -0
  58. dhruva-0.6.0/.archive/old_durus_package/durus/storage/file.py +196 -0
  59. dhruva-0.6.0/.archive/old_durus_package/durus/storage/sqlite.py +272 -0
  60. dhruva-0.6.0/.archive/old_durus_package/durus/storage_server.py +9 -0
  61. dhruva-0.6.0/.archive/old_durus_package/durus/utils.py +568 -0
  62. dhruva-0.6.0/ACKS.txt +30 -0
  63. dhruva-0.6.0/CHANGELOG.md +201 -0
  64. dhruva-0.6.0/CLAUDE.md +713 -0
  65. dhruva-0.6.0/DEPLOYMENT.md +548 -0
  66. dhruva-0.6.0/DHRUVA_MODES_QUICK_REFERENCE.md +310 -0
  67. dhruva-0.6.0/DHRUVA_OPERATIONAL_MODES_IMPLEMENTATION.md +308 -0
  68. dhruva-0.6.0/INSTALL.txt +41 -0
  69. dhruva-0.6.0/LICENSE.txt +26 -0
  70. dhruva-0.6.0/MANIFEST.in +6 -0
  71. dhruva-0.6.0/PKG-INFO +238 -0
  72. dhruva-0.6.0/README.md +207 -0
  73. dhruva-0.6.0/TEST_QUICK_REFERENCE.md +201 -0
  74. dhruva-0.6.0/benchmarks/__init__.py +14 -0
  75. dhruva-0.6.0/benchmarks/conftest.py +74 -0
  76. dhruva-0.6.0/benchmarks/test_cache.py +50 -0
  77. dhruva-0.6.0/benchmarks/test_fallback_performance.py +355 -0
  78. dhruva-0.6.0/benchmarks/test_operations.py +75 -0
  79. dhruva-0.6.0/benchmarks/test_serializers.py +128 -0
  80. dhruva-0.6.0/benchmarks/test_storage.py +0 -0
  81. dhruva-0.6.0/bin/db_renumber.py +47 -0
  82. dhruva-0.6.0/bin/db_to_py3k.py +105 -0
  83. dhruva-0.6.0/bin/durus +7 -0
  84. dhruva-0.6.0/deployment/scripts/generate_token.py +459 -0
  85. dhruva-0.6.0/dhruva/__init__.py +86 -0
  86. dhruva-0.6.0/dhruva/__main__.py +734 -0
  87. dhruva-0.6.0/dhruva/_compat.py +55 -0
  88. dhruva-0.6.0/dhruva/backup/__init__.py +32 -0
  89. dhruva-0.6.0/dhruva/backup/catalog.py +282 -0
  90. dhruva-0.6.0/dhruva/backup/cli.py +610 -0
  91. dhruva-0.6.0/dhruva/backup/manager.py +459 -0
  92. dhruva-0.6.0/dhruva/backup/restore.py +358 -0
  93. dhruva-0.6.0/dhruva/backup/scheduler.py +374 -0
  94. dhruva-0.6.0/dhruva/backup/storage.py +399 -0
  95. dhruva-0.6.0/dhruva/backup/verification.py +448 -0
  96. dhruva-0.6.0/dhruva/btree.py +9 -0
  97. dhruva-0.6.0/dhruva/cli.py +311 -0
  98. dhruva-0.6.0/dhruva/collections/__init__.py +21 -0
  99. dhruva-0.6.0/dhruva/collections/btree.py +635 -0
  100. dhruva-0.6.0/dhruva/collections/dict.py +131 -0
  101. dhruva-0.6.0/dhruva/collections/list.py +150 -0
  102. dhruva-0.6.0/dhruva/collections/set.py +188 -0
  103. dhruva-0.6.0/dhruva/config/__init__.py +39 -0
  104. dhruva-0.6.0/dhruva/config/defaults.py +185 -0
  105. dhruva-0.6.0/dhruva/config/loader.py +355 -0
  106. dhruva-0.6.0/dhruva/config/security.py +462 -0
  107. dhruva-0.6.0/dhruva/connection.py +9 -0
  108. dhruva-0.6.0/dhruva/core/__init__.py +25 -0
  109. dhruva-0.6.0/dhruva/core/config.py +164 -0
  110. dhruva-0.6.0/dhruva/core/connection.py +553 -0
  111. dhruva-0.6.0/dhruva/core/persistent.py +290 -0
  112. dhruva-0.6.0/dhruva/error.py +63 -0
  113. dhruva-0.6.0/dhruva/file.py +151 -0
  114. dhruva-0.6.0/dhruva/file_storage.py +9 -0
  115. dhruva-0.6.0/dhruva/file_storage2.py +358 -0
  116. dhruva-0.6.0/dhruva/logger.py +37 -0
  117. dhruva-0.6.0/dhruva/logging/__init__.py +29 -0
  118. dhruva-0.6.0/dhruva/logging/logger.py +232 -0
  119. dhruva-0.6.0/dhruva/mcp/__init__.py +33 -0
  120. dhruva-0.6.0/dhruva/mcp/adapter_tools.py +748 -0
  121. dhruva-0.6.0/dhruva/mcp/auth.py +856 -0
  122. dhruva-0.6.0/dhruva/mcp/middleware.py +423 -0
  123. dhruva-0.6.0/dhruva/mcp/oneiric_server.py +486 -0
  124. dhruva-0.6.0/dhruva/mcp/server.py +539 -0
  125. dhruva-0.6.0/dhruva/mcp/server_core.py +297 -0
  126. dhruva-0.6.0/dhruva/modes/__init__.py +54 -0
  127. dhruva-0.6.0/dhruva/modes/base.py +407 -0
  128. dhruva-0.6.0/dhruva/modes/lite.py +238 -0
  129. dhruva-0.6.0/dhruva/modes/standard.py +410 -0
  130. dhruva-0.6.0/dhruva/monitoring/__init__.py +25 -0
  131. dhruva-0.6.0/dhruva/monitoring/health.py +335 -0
  132. dhruva-0.6.0/dhruva/monitoring/metrics.py +312 -0
  133. dhruva-0.6.0/dhruva/monitoring/server.py +188 -0
  134. dhruva-0.6.0/dhruva/persistent.py +9 -0
  135. dhruva-0.6.0/dhruva/persistent_dict.py +11 -0
  136. dhruva-0.6.0/dhruva/persistent_list.py +9 -0
  137. dhruva-0.6.0/dhruva/persistent_set.py +9 -0
  138. dhruva-0.6.0/dhruva/security/__init__.py +48 -0
  139. dhruva-0.6.0/dhruva/security/oneiric_secrets.py +448 -0
  140. dhruva-0.6.0/dhruva/security/signing.py +329 -0
  141. dhruva-0.6.0/dhruva/security/tls.py +385 -0
  142. dhruva-0.6.0/dhruva/serialize/__init__.py +57 -0
  143. dhruva-0.6.0/dhruva/serialize/adapter.py +124 -0
  144. dhruva-0.6.0/dhruva/serialize/base.py +92 -0
  145. dhruva-0.6.0/dhruva/serialize/dill.py +127 -0
  146. dhruva-0.6.0/dhruva/serialize/factory.py +100 -0
  147. dhruva-0.6.0/dhruva/serialize/fallback.py +343 -0
  148. dhruva-0.6.0/dhruva/serialize/msgspec.py +183 -0
  149. dhruva-0.6.0/dhruva/serialize/pickle.py +88 -0
  150. dhruva-0.6.0/dhruva/serialize_legacy.py +242 -0
  151. dhruva-0.6.0/dhruva/server/__init__.py +14 -0
  152. dhruva-0.6.0/dhruva/server/server.py +616 -0
  153. dhruva-0.6.0/dhruva/server/socket.py +66 -0
  154. dhruva-0.6.0/dhruva/shelf.py +438 -0
  155. dhruva-0.6.0/dhruva/shell/__init__.py +363 -0
  156. dhruva-0.6.0/dhruva/shell/session_tracker.py +35 -0
  157. dhruva-0.6.0/dhruva/storage/__init__.py +31 -0
  158. dhruva-0.6.0/dhruva/storage/base.py +196 -0
  159. dhruva-0.6.0/dhruva/storage/client.py +210 -0
  160. dhruva-0.6.0/dhruva/storage/file.py +218 -0
  161. dhruva-0.6.0/dhruva/storage/sqlite.py +271 -0
  162. dhruva-0.6.0/dhruva/storage_server.py +9 -0
  163. dhruva-0.6.0/dhruva/utils.py +566 -0
  164. dhruva-0.6.0/dhruva.egg-info/PKG-INFO +238 -0
  165. dhruva-0.6.0/dhruva.egg-info/SOURCES.txt +210 -0
  166. dhruva-0.6.0/dhruva.egg-info/dependency_links.txt +1 -0
  167. dhruva-0.6.0/dhruva.egg-info/entry_points.txt +3 -0
  168. dhruva-0.6.0/dhruva.egg-info/requires.txt +6 -0
  169. dhruva-0.6.0/dhruva.egg-info/top_level.txt +1 -0
  170. dhruva-0.6.0/doc/CHANGES_CNRI.txt +658 -0
  171. dhruva-0.6.0/doc/FAQ.txt +155 -0
  172. dhruva-0.6.0/doc/LICENSE_CNRI.txt +65 -0
  173. dhruva-0.6.0/doc/README_CNRI.txt +161 -0
  174. dhruva-0.6.0/examples/backup_example.py +410 -0
  175. dhruva-0.6.0/examples/security_example.py +111 -0
  176. dhruva-0.6.0/pyproject.toml +194 -0
  177. dhruva-0.6.0/setup.cfg +4 -0
  178. dhruva-0.6.0/setup_backup_system.py +409 -0
  179. dhruva-0.6.0/test/__init__.py +1 -0
  180. dhruva-0.6.0/test/conftest.py +221 -0
  181. dhruva-0.6.0/test/stress.py +195 -0
  182. dhruva-0.6.0/test/test_btree.py +445 -0
  183. dhruva-0.6.0/test/test_btree_comprehensive.py +53 -0
  184. dhruva-0.6.0/test/test_btree_len.py +63 -0
  185. dhruva-0.6.0/test/test_client_storage.py +197 -0
  186. dhruva-0.6.0/test/test_config.py +441 -0
  187. dhruva-0.6.0/test/test_connection.py +327 -0
  188. dhruva-0.6.0/test/test_fallback_integration.py +322 -0
  189. dhruva-0.6.0/test/test_fallback_serializer.py +262 -0
  190. dhruva-0.6.0/test/test_file.py +84 -0
  191. dhruva-0.6.0/test/test_file_storage.py +208 -0
  192. dhruva-0.6.0/test/test_logging.py +264 -0
  193. dhruva-0.6.0/test/test_mcp_auth.py +799 -0
  194. dhruva-0.6.0/test/test_missing.py +71 -0
  195. dhruva-0.6.0/test/test_persistent_dict.py +138 -0
  196. dhruva-0.6.0/test/test_persistent_list.py +122 -0
  197. dhruva-0.6.0/test/test_persistent_set.py +320 -0
  198. dhruva-0.6.0/test/test_pypy_compat.py +67 -0
  199. dhruva-0.6.0/test/test_security.py +322 -0
  200. dhruva-0.6.0/test/test_serialize.py +74 -0
  201. dhruva-0.6.0/test/test_serializers.py +262 -0
  202. dhruva-0.6.0/test/test_shelf.py +58 -0
  203. dhruva-0.6.0/test/test_signing.py +276 -0
  204. dhruva-0.6.0/test/test_storage.py +37 -0
  205. dhruva-0.6.0/test/test_storage_server.py +29 -0
  206. dhruva-0.6.0/test/test_tls.py +287 -0
  207. dhruva-0.6.0/test/test_utils.py +325 -0
  208. dhruva-0.6.0/test/unit/test_adapter_registry.py +688 -0
  209. dhruva-0.6.0/test/unit/test_cli.py +461 -0
  210. dhruva-0.6.0/test/unit/test_config.py +327 -0
  211. dhruva-0.6.0/test/unit/test_mcp_server.py +363 -0
  212. dhruva-0.6.0/tests/integration/test_backup_restore.py +927 -0
@@ -0,0 +1,84 @@
1
+ """
2
+ Durus - Persistent Object Database for Python
3
+
4
+ Copyright (c) Corporation for National Research Initiatives 2009. All Rights Reserved.
5
+ Modernized for Python 3.13+ with Oneiric ecosystem integration.
6
+ """
7
+
8
+ __version__ = "5.0.0"
9
+
10
+ # Core persistence framework
11
+ from dhruva.core import Connection, Persistent, PersistentBase
12
+
13
+ # Storage backends
14
+ from dhruva.storage import Storage, FileStorage, SqliteStorage, ClientStorage
15
+
16
+ # Persistent collections
17
+ from dhruva.collections import (
18
+ PersistentDict,
19
+ PersistentList,
20
+ PersistentSet,
21
+ BTree,
22
+ BNode,
23
+ )
24
+
25
+ # Storage server
26
+ from dhruva.server import StorageServer, wait_for_server
27
+
28
+ # Serialization
29
+ from dhruva.serialize import Serializer, MsgspecSerializer, PickleSerializer
30
+
31
+ # Utilities
32
+ from dhruva.utils import (
33
+ as_bytes,
34
+ int8_to_str,
35
+ int4_to_str,
36
+ str_to_int8,
37
+ str_to_int4,
38
+ )
39
+
40
+ # Errors
41
+ from dhruva.error import (
42
+ ConflictError,
43
+ ReadConflictError,
44
+ WriteConflictError,
45
+ DurusKeyError,
46
+ )
47
+
48
+ __all__ = [
49
+ # Version
50
+ '__version__',
51
+ # Core
52
+ 'Connection',
53
+ 'Persistent',
54
+ 'PersistentBase',
55
+ # Storage
56
+ 'Storage',
57
+ 'FileStorage',
58
+ 'SqliteStorage',
59
+ 'ClientStorage',
60
+ # Collections
61
+ 'PersistentDict',
62
+ 'PersistentList',
63
+ 'PersistentSet',
64
+ 'BTree',
65
+ 'BNode',
66
+ # Server
67
+ 'StorageServer',
68
+ 'wait_for_server',
69
+ # Serialization
70
+ 'Serializer',
71
+ 'MsgspecSerializer',
72
+ 'PickleSerializer',
73
+ # Utilities
74
+ 'as_bytes',
75
+ 'int8_to_str',
76
+ 'int4_to_str',
77
+ 'str_to_int8',
78
+ 'str_to_int4',
79
+ # Errors
80
+ 'ConflictError',
81
+ 'ReadConflictError',
82
+ 'WriteConflictError',
83
+ 'DurusKeyError',
84
+ ]
@@ -0,0 +1,441 @@
1
+ #!/usr/bin/env python
2
+ """
3
+ $URL$
4
+ $Id$
5
+ """
6
+
7
+ import os
8
+ import socket
9
+ import sys
10
+ from code import InteractiveConsole
11
+ from optparse import OptionParser
12
+ from pprint import pprint
13
+ from time import sleep
14
+ from types import ModuleType
15
+
16
+ from dhruva.storage.client import ClientStorage
17
+ from dhruva.core import Connection
18
+ from dhruva.logger import direct_output, log, logger
19
+ from dhruva.server.server import (
20
+ DEFAULT_GCBYTES,
21
+ DEFAULT_HOST,
22
+ DEFAULT_PORT,
23
+ SocketAddress,
24
+ StorageServer,
25
+ wait_for_server,
26
+ )
27
+ from dhruva.utils import int8_to_str, str_to_int8, write
28
+
29
+
30
+ def configure_readline(namespace, history_path):
31
+ try:
32
+ import atexit
33
+ import readline
34
+ import rlcompleter
35
+
36
+ readline.set_completer(rlcompleter.Completer(namespace=namespace).complete)
37
+ readline.parse_and_bind("tab: complete")
38
+
39
+ def save_history(history_path=history_path):
40
+ readline.write_history_file(history_path)
41
+
42
+ atexit.register(save_history)
43
+ if os.path.exists(history_path):
44
+ readline.read_history_file(history_path)
45
+ except ImportError:
46
+ pass
47
+
48
+
49
+ def interactive_client(
50
+ file, address, cache_size, readonly, repair, startup, storage_class=None
51
+ ):
52
+ if file:
53
+ storage = get_storage(
54
+ file, storage_class=storage_class, readonly=readonly, repair=repair
55
+ )
56
+ description = file
57
+ else:
58
+ socket_address = SocketAddress.new(address)
59
+ wait_for_server(address=socket_address)
60
+ storage = ClientStorage(address=socket_address)
61
+ description = socket_address
62
+ connection = Connection(storage, cache_size=cache_size)
63
+ console_module = ModuleType("__console__")
64
+ sys.modules["__console__"] = console_module
65
+ namespace = {
66
+ "connection": connection,
67
+ "root": connection.get_root(),
68
+ "get": connection.get,
69
+ "sys": sys,
70
+ "os": os,
71
+ "int8_to_str": int8_to_str,
72
+ "str_to_int8": str_to_int8,
73
+ "pp": pprint,
74
+ }
75
+ vars(console_module).update(namespace)
76
+ configure_readline(vars(console_module), os.path.expanduser("~/.durushistory"))
77
+ console = InteractiveConsole(vars(console_module))
78
+ if startup:
79
+ console.runsource('execfile("%s")' % os.path.expanduser(startup))
80
+ help = " connection -> the Connection\n root -> the root instance"
81
+ console.interact("Durus %s\n%s" % (description, help))
82
+
83
+
84
+ def client_main():
85
+ from optparse import OptionParser
86
+
87
+ parser = OptionParser()
88
+ parser.set_description("Opens a client connection to a Durus server.")
89
+ parser.add_option(
90
+ "--file",
91
+ dest="file",
92
+ default=None,
93
+ help="If this is not given, the storage is through a Durus server.",
94
+ )
95
+ parser.add_option(
96
+ "--port",
97
+ dest="port",
98
+ default=DEFAULT_PORT,
99
+ type="int",
100
+ help="Port the server is on. (default=%s)" % DEFAULT_PORT,
101
+ )
102
+ parser.add_option(
103
+ "--host",
104
+ dest="host",
105
+ default=DEFAULT_HOST,
106
+ help="Host of the server. (default=%s)" % DEFAULT_HOST,
107
+ )
108
+ parser.add_option(
109
+ "--address",
110
+ dest="address",
111
+ default=None,
112
+ help=(
113
+ "Address of the server.\n"
114
+ "If given, this is the path to a Unix domain socket for "
115
+ "the server."
116
+ ),
117
+ )
118
+ parser.add_option(
119
+ "--storage-class",
120
+ dest="storage",
121
+ default=None,
122
+ help="Storage class (e.g. durus.file_storage.FileStorage).",
123
+ )
124
+ parser.add_option(
125
+ "--cache_size",
126
+ dest="cache_size",
127
+ default=10000,
128
+ type="int",
129
+ help="Size of client cache (default=10000)",
130
+ )
131
+ parser.add_option(
132
+ "--repair",
133
+ dest="repair",
134
+ action="store_true",
135
+ help=(
136
+ "Repair the filestorage by truncating to remove anything "
137
+ "that is malformed. Without this option, errors "
138
+ "will cause the program to report and terminate without "
139
+ "attempting any repair."
140
+ ),
141
+ )
142
+ parser.add_option(
143
+ "--readonly",
144
+ dest="readonly",
145
+ action="store_true",
146
+ help="Open the file in read-only mode.",
147
+ )
148
+ parser.add_option(
149
+ "--startup",
150
+ dest="startup",
151
+ default=os.environ.get("DURUSSTARTUP", ""),
152
+ help=(
153
+ "Full path to a python startup file to execute on startup."
154
+ "(default=DURUSSTARTUP from environment, if set)"
155
+ ),
156
+ )
157
+ (options, args) = parser.parse_args()
158
+ if options.address is None:
159
+ address = (options.host, options.port)
160
+ else:
161
+ address = options.address
162
+ interactive_client(
163
+ options.file,
164
+ address,
165
+ options.cache_size,
166
+ options.readonly,
167
+ options.repair,
168
+ options.startup,
169
+ options.storage,
170
+ )
171
+
172
+
173
+ def get_storage_class(file):
174
+ """Return the corresponding storage class based on an existing file."""
175
+ if not os.path.exists(file):
176
+ from dhruva.file_storage import FileStorage
177
+
178
+ return FileStorage
179
+ fp = open(file, "rb")
180
+ d = fp.read(20)
181
+ fp.close()
182
+ if d.startswith(b"DFS20"):
183
+ from dhruva.file_storage2 import FileStorage2
184
+
185
+ return FileStorage2
186
+ elif d.startswith(b"SQLite format "):
187
+ from dhruva.sqlite_storage import SqliteStorage
188
+
189
+ return SqliteStorage
190
+ elif d.startswith(b"SHELF-1"):
191
+ from dhruva.file_storage import FileStorage
192
+
193
+ return FileStorage
194
+ else:
195
+ raise ValueError("unknown storage type for file")
196
+
197
+
198
+ def import_class(name):
199
+ module_name, _, class_name = name.rpartition(".")
200
+ module = __import__(module_name, globals(), locals(), [class_name])
201
+ return getattr(module, class_name)
202
+
203
+
204
+ def get_storage(file, storage_class=None, **kwargs):
205
+ if storage_class is not None:
206
+ storage_class = import_class(storage_class)
207
+ else:
208
+ if file is None:
209
+ from dhruva.file_storage import FileStorage
210
+
211
+ # passing file=None will create temporary storage
212
+ storage_class = FileStorage
213
+ else:
214
+ storage_class = get_storage_class(file)
215
+ return storage_class(file, **kwargs)
216
+
217
+
218
+ def start_durus(logfile, logginglevel, address, storage, gcbytes):
219
+ if logfile is None:
220
+ logfile = sys.stderr
221
+ else:
222
+ logfile = open(logfile, "a+")
223
+ direct_output(logfile)
224
+ logger.setLevel(logginglevel)
225
+ socket_address = SocketAddress.new(address)
226
+ if hasattr(storage, "get_filename"):
227
+ log(20, "Storage file=%s address=%s", storage.get_filename(), socket_address)
228
+ StorageServer(storage, address=socket_address, gcbytes=gcbytes).serve()
229
+
230
+
231
+ def stop_durus(address):
232
+ socket_address = SocketAddress.new(address)
233
+ sock = socket_address.get_connected_socket()
234
+ if sock is None:
235
+ log(20, "Durus server %s doesn't seem to be running." % str(address))
236
+ return False
237
+ write(sock, "Q") # graceful exit message
238
+ sock.close()
239
+ # Try to wait until the address is free.
240
+ for attempt in range(20):
241
+ sleep(0.5)
242
+ sock = socket_address.get_connected_socket()
243
+ if sock is None:
244
+ break
245
+ sock.close()
246
+ return True
247
+
248
+
249
+ def run_durus_main():
250
+ parser = OptionParser()
251
+ parser.set_description("Run a Durus Server")
252
+ parser.add_option(
253
+ "--port",
254
+ dest="port",
255
+ default=DEFAULT_PORT,
256
+ type="int",
257
+ help="Port to listen on. (default=%s)" % DEFAULT_PORT,
258
+ )
259
+ parser.add_option(
260
+ "--file",
261
+ dest="file",
262
+ default=None,
263
+ help=("If not given, the storage is in a new temporary file."),
264
+ )
265
+ parser.add_option(
266
+ "--host",
267
+ dest="host",
268
+ default=DEFAULT_HOST,
269
+ help="Host to listen on. (default=%s)" % DEFAULT_HOST,
270
+ )
271
+ parser.add_option(
272
+ "--storage-class",
273
+ dest="storage",
274
+ default=None,
275
+ help="Storage class (e.g. durus.file_storage.FileStorage).",
276
+ )
277
+ parser.add_option(
278
+ "--gcbytes",
279
+ dest="gcbytes",
280
+ default=DEFAULT_GCBYTES,
281
+ type="int",
282
+ help=(
283
+ "Trigger garbage collection after this many commits. (default=%s)"
284
+ % DEFAULT_GCBYTES
285
+ ),
286
+ )
287
+ if hasattr(socket, "AF_UNIX"):
288
+ parser.add_option(
289
+ "--address",
290
+ dest="address",
291
+ default=None,
292
+ help=(
293
+ "Address of the server.\n"
294
+ "If given, this is the path to a Unix domain socket for "
295
+ "the server."
296
+ ),
297
+ )
298
+ parser.add_option(
299
+ "--owner",
300
+ dest="owner",
301
+ default=None,
302
+ help="Owner of the Unix domain socket (the --address value).",
303
+ )
304
+ parser.add_option(
305
+ "--group",
306
+ dest="group",
307
+ default=None,
308
+ help="group of the Unix domain socket (the --address value).",
309
+ )
310
+ parser.add_option(
311
+ "--umask",
312
+ dest="umask",
313
+ default=None,
314
+ type="int",
315
+ help="umask for the Unix domain socket (the --address value).",
316
+ )
317
+ logginglevel = logger.getEffectiveLevel()
318
+ parser.add_option(
319
+ "--logginglevel",
320
+ dest="logginglevel",
321
+ default=logginglevel,
322
+ type="int",
323
+ help=(
324
+ "Logging level. Lower positive numbers log more. (default=%s)"
325
+ % logginglevel
326
+ ),
327
+ )
328
+ parser.add_option(
329
+ "--logfile", dest="logfile", default=None, help=("Log file. (default=stderr)")
330
+ )
331
+ parser.add_option(
332
+ "--repair",
333
+ dest="repair",
334
+ action="store_true",
335
+ help=(
336
+ "Repair the filestorage by truncating to remove anything "
337
+ "that is malformed. Without this option, errors "
338
+ "will cause the program to report and terminate without "
339
+ "attempting any repair."
340
+ ),
341
+ )
342
+ parser.add_option(
343
+ "--readonly",
344
+ dest="readonly",
345
+ action="store_true",
346
+ help="Open the file in read-only mode.",
347
+ )
348
+ parser.add_option(
349
+ "--stop",
350
+ dest="stop",
351
+ action="store_true",
352
+ help="Instead of starting the server, try to stop a running one.",
353
+ )
354
+ (options, args) = parser.parse_args()
355
+ if getattr(options, "address", None) is None:
356
+ address = SocketAddress.new((options.host, options.port))
357
+ elif options.address.startswith("@"):
358
+ # abstract unix socket
359
+ address = SocketAddress.new(address=options.address)
360
+ else:
361
+ # unix socket
362
+ address = SocketAddress.new(
363
+ address=options.address,
364
+ owner=options.owner,
365
+ group=options.group,
366
+ umask=options.umask,
367
+ )
368
+ if not options.stop:
369
+ storage = get_storage(
370
+ options.file,
371
+ storage_class=options.storage,
372
+ repair=options.repair,
373
+ readonly=options.readonly,
374
+ )
375
+ start_durus(
376
+ options.logfile, options.logginglevel, address, storage, options.gcbytes
377
+ )
378
+ else:
379
+ stop_durus(address)
380
+
381
+
382
+ def pack_storage_main():
383
+ parser = OptionParser()
384
+ parser.set_description("Packs a Durus storage.")
385
+ parser.add_option(
386
+ "--file",
387
+ dest="file",
388
+ default=None,
389
+ help="If this is not given, the storage is through a Durus server.",
390
+ )
391
+ parser.add_option(
392
+ "--port",
393
+ dest="port",
394
+ default=DEFAULT_PORT,
395
+ type="int",
396
+ help="Port the server is on. (default=%s)" % DEFAULT_PORT,
397
+ )
398
+ parser.add_option(
399
+ "--host",
400
+ dest="host",
401
+ default=DEFAULT_HOST,
402
+ help="Host of the server. (default=%s)" % DEFAULT_HOST,
403
+ )
404
+ (options, args) = parser.parse_args()
405
+ if options.file is None:
406
+ wait_for_server(options.host, options.port)
407
+ storage = ClientStorage(host=options.host, port=options.port)
408
+ else:
409
+ storage = get_storage(options.file)
410
+ connection = Connection(storage)
411
+ connection.pack()
412
+
413
+
414
+ def usage():
415
+ sys.stdout.write(
416
+ "durus [ -c | -s | -p ] [ -h ] [<specific options>]\n"
417
+ " -s Start or stop a Durus storage server.\n"
418
+ " -c Start a low-level interactive client.\n"
419
+ " -p Pack a storage file.\n"
420
+ " -h Get help on specific options.\n"
421
+ )
422
+
423
+
424
+ def main():
425
+ if len(sys.argv) == 1:
426
+ usage()
427
+ else:
428
+ arg = sys.argv[1]
429
+ sys.argv[1:] = sys.argv[2:]
430
+ if arg == "-c":
431
+ client_main()
432
+ elif arg == "-s":
433
+ run_durus_main()
434
+ elif arg == "-p":
435
+ pack_storage_main()
436
+ else:
437
+ usage()
438
+
439
+
440
+ if __name__ == "__main__":
441
+ main()
@@ -0,0 +1,32 @@
1
+ """
2
+ Backup and restore system for Durus database.
3
+
4
+ This package provides comprehensive backup and restore capabilities for Durus databases,
5
+ including:
6
+
7
+ - Full, incremental, and differential backups
8
+ - Automated scheduling
9
+ - Compression and encryption
10
+ - Cloud storage integration
11
+ - Point-in-time recovery
12
+ - Backup verification and testing
13
+ """
14
+
15
+ from .manager import BackupManager
16
+ from .restore import RestoreManager
17
+ from .catalog import BackupCatalog
18
+ from .scheduler import BackupScheduler
19
+ from .storage import StorageAdapter, S3Storage, GCSStorage, AzureBlobStorage
20
+ from .verification import BackupVerification
21
+
22
+ __all__ = [
23
+ 'BackupManager',
24
+ 'RestoreManager',
25
+ 'BackupCatalog',
26
+ 'BackupScheduler',
27
+ 'StorageAdapter',
28
+ 'S3Storage',
29
+ 'GCSStorage',
30
+ 'AzureBlobStorage',
31
+ 'BackupVerification',
32
+ ]