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.
- dhruva-0.6.0/.archive/old_durus_package/durus/__init__.py +84 -0
- dhruva-0.6.0/.archive/old_durus_package/durus/__main__.py +441 -0
- dhruva-0.6.0/.archive/old_durus_package/durus/backup/__init__.py +32 -0
- dhruva-0.6.0/.archive/old_durus_package/durus/backup/catalog.py +271 -0
- dhruva-0.6.0/.archive/old_durus_package/durus/backup/cli.py +525 -0
- dhruva-0.6.0/.archive/old_durus_package/durus/backup/manager.py +440 -0
- dhruva-0.6.0/.archive/old_durus_package/durus/backup/restore.py +336 -0
- dhruva-0.6.0/.archive/old_durus_package/durus/backup/scheduler.py +368 -0
- dhruva-0.6.0/.archive/old_durus_package/durus/backup/storage.py +386 -0
- dhruva-0.6.0/.archive/old_durus_package/durus/backup/verification.py +436 -0
- dhruva-0.6.0/.archive/old_durus_package/durus/btree.py +9 -0
- dhruva-0.6.0/.archive/old_durus_package/durus/collections/__init__.py +21 -0
- dhruva-0.6.0/.archive/old_durus_package/durus/collections/btree.py +598 -0
- dhruva-0.6.0/.archive/old_durus_package/durus/collections/dict.py +131 -0
- dhruva-0.6.0/.archive/old_durus_package/durus/collections/list.py +150 -0
- dhruva-0.6.0/.archive/old_durus_package/durus/collections/set.py +189 -0
- dhruva-0.6.0/.archive/old_durus_package/durus/config/__init__.py +39 -0
- dhruva-0.6.0/.archive/old_durus_package/durus/config/defaults.py +177 -0
- dhruva-0.6.0/.archive/old_durus_package/durus/config/loader.py +355 -0
- dhruva-0.6.0/.archive/old_durus_package/durus/config/security.py +451 -0
- dhruva-0.6.0/.archive/old_durus_package/durus/connection.py +9 -0
- dhruva-0.6.0/.archive/old_durus_package/durus/core/__init__.py +20 -0
- dhruva-0.6.0/.archive/old_durus_package/durus/core/connection.py +530 -0
- dhruva-0.6.0/.archive/old_durus_package/durus/core/persistent.py +290 -0
- dhruva-0.6.0/.archive/old_durus_package/durus/error.py +59 -0
- dhruva-0.6.0/.archive/old_durus_package/durus/file.py +148 -0
- dhruva-0.6.0/.archive/old_durus_package/durus/file_storage.py +9 -0
- dhruva-0.6.0/.archive/old_durus_package/durus/file_storage2.py +360 -0
- dhruva-0.6.0/.archive/old_durus_package/durus/logger.py +37 -0
- dhruva-0.6.0/.archive/old_durus_package/durus/logging/__init__.py +29 -0
- dhruva-0.6.0/.archive/old_durus_package/durus/logging/logger.py +233 -0
- dhruva-0.6.0/.archive/old_durus_package/durus/mcp/__init__.py +33 -0
- dhruva-0.6.0/.archive/old_durus_package/durus/mcp/auth.py +863 -0
- dhruva-0.6.0/.archive/old_durus_package/durus/mcp/middleware.py +423 -0
- dhruva-0.6.0/.archive/old_durus_package/durus/mcp/oneiric_server.py +483 -0
- dhruva-0.6.0/.archive/old_durus_package/durus/mcp/server.py +543 -0
- dhruva-0.6.0/.archive/old_durus_package/durus/persistent.py +9 -0
- dhruva-0.6.0/.archive/old_durus_package/durus/persistent_dict.py +11 -0
- dhruva-0.6.0/.archive/old_durus_package/durus/persistent_list.py +9 -0
- dhruva-0.6.0/.archive/old_durus_package/durus/persistent_set.py +9 -0
- dhruva-0.6.0/.archive/old_durus_package/durus/security/__init__.py +26 -0
- dhruva-0.6.0/.archive/old_durus_package/durus/security/oneiric_secrets.py +432 -0
- dhruva-0.6.0/.archive/old_durus_package/durus/serialize/__init__.py +53 -0
- dhruva-0.6.0/.archive/old_durus_package/durus/serialize/adapter.py +118 -0
- dhruva-0.6.0/.archive/old_durus_package/durus/serialize/base.py +92 -0
- dhruva-0.6.0/.archive/old_durus_package/durus/serialize/dill.py +125 -0
- dhruva-0.6.0/.archive/old_durus_package/durus/serialize/factory.py +79 -0
- dhruva-0.6.0/.archive/old_durus_package/durus/serialize/msgspec.py +124 -0
- dhruva-0.6.0/.archive/old_durus_package/durus/serialize/pickle.py +87 -0
- dhruva-0.6.0/.archive/old_durus_package/durus/serialize_legacy.py +242 -0
- dhruva-0.6.0/.archive/old_durus_package/durus/server/__init__.py +14 -0
- dhruva-0.6.0/.archive/old_durus_package/durus/server/server.py +526 -0
- dhruva-0.6.0/.archive/old_durus_package/durus/server/socket.py +66 -0
- dhruva-0.6.0/.archive/old_durus_package/durus/shelf.py +442 -0
- dhruva-0.6.0/.archive/old_durus_package/durus/storage/__init__.py +25 -0
- dhruva-0.6.0/.archive/old_durus_package/durus/storage/base.py +196 -0
- dhruva-0.6.0/.archive/old_durus_package/durus/storage/client.py +154 -0
- dhruva-0.6.0/.archive/old_durus_package/durus/storage/file.py +196 -0
- dhruva-0.6.0/.archive/old_durus_package/durus/storage/sqlite.py +272 -0
- dhruva-0.6.0/.archive/old_durus_package/durus/storage_server.py +9 -0
- dhruva-0.6.0/.archive/old_durus_package/durus/utils.py +568 -0
- dhruva-0.6.0/ACKS.txt +30 -0
- dhruva-0.6.0/CHANGELOG.md +201 -0
- dhruva-0.6.0/CLAUDE.md +713 -0
- dhruva-0.6.0/DEPLOYMENT.md +548 -0
- dhruva-0.6.0/DHRUVA_MODES_QUICK_REFERENCE.md +310 -0
- dhruva-0.6.0/DHRUVA_OPERATIONAL_MODES_IMPLEMENTATION.md +308 -0
- dhruva-0.6.0/INSTALL.txt +41 -0
- dhruva-0.6.0/LICENSE.txt +26 -0
- dhruva-0.6.0/MANIFEST.in +6 -0
- dhruva-0.6.0/PKG-INFO +238 -0
- dhruva-0.6.0/README.md +207 -0
- dhruva-0.6.0/TEST_QUICK_REFERENCE.md +201 -0
- dhruva-0.6.0/benchmarks/__init__.py +14 -0
- dhruva-0.6.0/benchmarks/conftest.py +74 -0
- dhruva-0.6.0/benchmarks/test_cache.py +50 -0
- dhruva-0.6.0/benchmarks/test_fallback_performance.py +355 -0
- dhruva-0.6.0/benchmarks/test_operations.py +75 -0
- dhruva-0.6.0/benchmarks/test_serializers.py +128 -0
- dhruva-0.6.0/benchmarks/test_storage.py +0 -0
- dhruva-0.6.0/bin/db_renumber.py +47 -0
- dhruva-0.6.0/bin/db_to_py3k.py +105 -0
- dhruva-0.6.0/bin/durus +7 -0
- dhruva-0.6.0/deployment/scripts/generate_token.py +459 -0
- dhruva-0.6.0/dhruva/__init__.py +86 -0
- dhruva-0.6.0/dhruva/__main__.py +734 -0
- dhruva-0.6.0/dhruva/_compat.py +55 -0
- dhruva-0.6.0/dhruva/backup/__init__.py +32 -0
- dhruva-0.6.0/dhruva/backup/catalog.py +282 -0
- dhruva-0.6.0/dhruva/backup/cli.py +610 -0
- dhruva-0.6.0/dhruva/backup/manager.py +459 -0
- dhruva-0.6.0/dhruva/backup/restore.py +358 -0
- dhruva-0.6.0/dhruva/backup/scheduler.py +374 -0
- dhruva-0.6.0/dhruva/backup/storage.py +399 -0
- dhruva-0.6.0/dhruva/backup/verification.py +448 -0
- dhruva-0.6.0/dhruva/btree.py +9 -0
- dhruva-0.6.0/dhruva/cli.py +311 -0
- dhruva-0.6.0/dhruva/collections/__init__.py +21 -0
- dhruva-0.6.0/dhruva/collections/btree.py +635 -0
- dhruva-0.6.0/dhruva/collections/dict.py +131 -0
- dhruva-0.6.0/dhruva/collections/list.py +150 -0
- dhruva-0.6.0/dhruva/collections/set.py +188 -0
- dhruva-0.6.0/dhruva/config/__init__.py +39 -0
- dhruva-0.6.0/dhruva/config/defaults.py +185 -0
- dhruva-0.6.0/dhruva/config/loader.py +355 -0
- dhruva-0.6.0/dhruva/config/security.py +462 -0
- dhruva-0.6.0/dhruva/connection.py +9 -0
- dhruva-0.6.0/dhruva/core/__init__.py +25 -0
- dhruva-0.6.0/dhruva/core/config.py +164 -0
- dhruva-0.6.0/dhruva/core/connection.py +553 -0
- dhruva-0.6.0/dhruva/core/persistent.py +290 -0
- dhruva-0.6.0/dhruva/error.py +63 -0
- dhruva-0.6.0/dhruva/file.py +151 -0
- dhruva-0.6.0/dhruva/file_storage.py +9 -0
- dhruva-0.6.0/dhruva/file_storage2.py +358 -0
- dhruva-0.6.0/dhruva/logger.py +37 -0
- dhruva-0.6.0/dhruva/logging/__init__.py +29 -0
- dhruva-0.6.0/dhruva/logging/logger.py +232 -0
- dhruva-0.6.0/dhruva/mcp/__init__.py +33 -0
- dhruva-0.6.0/dhruva/mcp/adapter_tools.py +748 -0
- dhruva-0.6.0/dhruva/mcp/auth.py +856 -0
- dhruva-0.6.0/dhruva/mcp/middleware.py +423 -0
- dhruva-0.6.0/dhruva/mcp/oneiric_server.py +486 -0
- dhruva-0.6.0/dhruva/mcp/server.py +539 -0
- dhruva-0.6.0/dhruva/mcp/server_core.py +297 -0
- dhruva-0.6.0/dhruva/modes/__init__.py +54 -0
- dhruva-0.6.0/dhruva/modes/base.py +407 -0
- dhruva-0.6.0/dhruva/modes/lite.py +238 -0
- dhruva-0.6.0/dhruva/modes/standard.py +410 -0
- dhruva-0.6.0/dhruva/monitoring/__init__.py +25 -0
- dhruva-0.6.0/dhruva/monitoring/health.py +335 -0
- dhruva-0.6.0/dhruva/monitoring/metrics.py +312 -0
- dhruva-0.6.0/dhruva/monitoring/server.py +188 -0
- dhruva-0.6.0/dhruva/persistent.py +9 -0
- dhruva-0.6.0/dhruva/persistent_dict.py +11 -0
- dhruva-0.6.0/dhruva/persistent_list.py +9 -0
- dhruva-0.6.0/dhruva/persistent_set.py +9 -0
- dhruva-0.6.0/dhruva/security/__init__.py +48 -0
- dhruva-0.6.0/dhruva/security/oneiric_secrets.py +448 -0
- dhruva-0.6.0/dhruva/security/signing.py +329 -0
- dhruva-0.6.0/dhruva/security/tls.py +385 -0
- dhruva-0.6.0/dhruva/serialize/__init__.py +57 -0
- dhruva-0.6.0/dhruva/serialize/adapter.py +124 -0
- dhruva-0.6.0/dhruva/serialize/base.py +92 -0
- dhruva-0.6.0/dhruva/serialize/dill.py +127 -0
- dhruva-0.6.0/dhruva/serialize/factory.py +100 -0
- dhruva-0.6.0/dhruva/serialize/fallback.py +343 -0
- dhruva-0.6.0/dhruva/serialize/msgspec.py +183 -0
- dhruva-0.6.0/dhruva/serialize/pickle.py +88 -0
- dhruva-0.6.0/dhruva/serialize_legacy.py +242 -0
- dhruva-0.6.0/dhruva/server/__init__.py +14 -0
- dhruva-0.6.0/dhruva/server/server.py +616 -0
- dhruva-0.6.0/dhruva/server/socket.py +66 -0
- dhruva-0.6.0/dhruva/shelf.py +438 -0
- dhruva-0.6.0/dhruva/shell/__init__.py +363 -0
- dhruva-0.6.0/dhruva/shell/session_tracker.py +35 -0
- dhruva-0.6.0/dhruva/storage/__init__.py +31 -0
- dhruva-0.6.0/dhruva/storage/base.py +196 -0
- dhruva-0.6.0/dhruva/storage/client.py +210 -0
- dhruva-0.6.0/dhruva/storage/file.py +218 -0
- dhruva-0.6.0/dhruva/storage/sqlite.py +271 -0
- dhruva-0.6.0/dhruva/storage_server.py +9 -0
- dhruva-0.6.0/dhruva/utils.py +566 -0
- dhruva-0.6.0/dhruva.egg-info/PKG-INFO +238 -0
- dhruva-0.6.0/dhruva.egg-info/SOURCES.txt +210 -0
- dhruva-0.6.0/dhruva.egg-info/dependency_links.txt +1 -0
- dhruva-0.6.0/dhruva.egg-info/entry_points.txt +3 -0
- dhruva-0.6.0/dhruva.egg-info/requires.txt +6 -0
- dhruva-0.6.0/dhruva.egg-info/top_level.txt +1 -0
- dhruva-0.6.0/doc/CHANGES_CNRI.txt +658 -0
- dhruva-0.6.0/doc/FAQ.txt +155 -0
- dhruva-0.6.0/doc/LICENSE_CNRI.txt +65 -0
- dhruva-0.6.0/doc/README_CNRI.txt +161 -0
- dhruva-0.6.0/examples/backup_example.py +410 -0
- dhruva-0.6.0/examples/security_example.py +111 -0
- dhruva-0.6.0/pyproject.toml +194 -0
- dhruva-0.6.0/setup.cfg +4 -0
- dhruva-0.6.0/setup_backup_system.py +409 -0
- dhruva-0.6.0/test/__init__.py +1 -0
- dhruva-0.6.0/test/conftest.py +221 -0
- dhruva-0.6.0/test/stress.py +195 -0
- dhruva-0.6.0/test/test_btree.py +445 -0
- dhruva-0.6.0/test/test_btree_comprehensive.py +53 -0
- dhruva-0.6.0/test/test_btree_len.py +63 -0
- dhruva-0.6.0/test/test_client_storage.py +197 -0
- dhruva-0.6.0/test/test_config.py +441 -0
- dhruva-0.6.0/test/test_connection.py +327 -0
- dhruva-0.6.0/test/test_fallback_integration.py +322 -0
- dhruva-0.6.0/test/test_fallback_serializer.py +262 -0
- dhruva-0.6.0/test/test_file.py +84 -0
- dhruva-0.6.0/test/test_file_storage.py +208 -0
- dhruva-0.6.0/test/test_logging.py +264 -0
- dhruva-0.6.0/test/test_mcp_auth.py +799 -0
- dhruva-0.6.0/test/test_missing.py +71 -0
- dhruva-0.6.0/test/test_persistent_dict.py +138 -0
- dhruva-0.6.0/test/test_persistent_list.py +122 -0
- dhruva-0.6.0/test/test_persistent_set.py +320 -0
- dhruva-0.6.0/test/test_pypy_compat.py +67 -0
- dhruva-0.6.0/test/test_security.py +322 -0
- dhruva-0.6.0/test/test_serialize.py +74 -0
- dhruva-0.6.0/test/test_serializers.py +262 -0
- dhruva-0.6.0/test/test_shelf.py +58 -0
- dhruva-0.6.0/test/test_signing.py +276 -0
- dhruva-0.6.0/test/test_storage.py +37 -0
- dhruva-0.6.0/test/test_storage_server.py +29 -0
- dhruva-0.6.0/test/test_tls.py +287 -0
- dhruva-0.6.0/test/test_utils.py +325 -0
- dhruva-0.6.0/test/unit/test_adapter_registry.py +688 -0
- dhruva-0.6.0/test/unit/test_cli.py +461 -0
- dhruva-0.6.0/test/unit/test_config.py +327 -0
- dhruva-0.6.0/test/unit/test_mcp_server.py +363 -0
- 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
|
+
]
|