stratum-db 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
stratum/__init__.py ADDED
File without changes
stratum/api.py ADDED
@@ -0,0 +1,41 @@
1
+ import os
2
+ import logging
3
+ from pathlib import Path
4
+
5
+ from dotenv import load_dotenv
6
+
7
+ load_dotenv()
8
+
9
+ def _get_config():
10
+ data_dir = Path(os.environ.get("STRATUM_DATA_DIR","./data"))
11
+
12
+ table_dir_raw = os.environ.get("STRATUM_TABLE_DIR")
13
+ table_dir = Path(table_dir_raw) if table_dir_raw else None
14
+
15
+ port_raw = os.environ.get("STRATUM_PORT","50051")
16
+
17
+ try:
18
+ port = int(port_raw)
19
+ except ValueError:
20
+ raise ValueError(
21
+ f"STRATUM_PORT must be an integer, got {port_raw!r}"
22
+ )
23
+
24
+ log_level_name = os.environ.get("STRATUM_LOG_LEVEL","INFO").upper()
25
+ log_level = getattr(logging, log_level_name)
26
+ if not isinstance(log_level, int):
27
+ raise ValueError(
28
+ f"STRATUM_LOG_LEVEL must be a valid level name, got {log_level_name!r}"
29
+ )
30
+
31
+ return data_dir, table_dir, port, log_level
32
+
33
+ def main():
34
+ data_dir, table_dir, port, log_level = _get_config()
35
+ logging.basicConfig(level=log_level)
36
+
37
+ from stratum.grpc.server import serve
38
+ serve(data_dir = data_dir, table_dir=table_dir, port=port)
39
+
40
+ if __name__ == "__main__":
41
+ main()
stratum/db.py ADDED
@@ -0,0 +1,90 @@
1
+ import os
2
+
3
+
4
+ _metadata_enabled = os.environ.get("STRATUM_METADATA_ENABLED", "false").strip().lower()
5
+ if _metadata_enabled not in {"1", "true", "yes", "on", "0", "false", "no", "off"}:
6
+ raise ValueError(
7
+ "STRATUM_METADATA_ENABLED must be a boolean value (true/false, 1/0, yes/no, or on/off)"
8
+ )
9
+ METADATA_ENABLED = _metadata_enabled in {"1", "true", "yes", "on"}
10
+
11
+
12
+ if METADATA_ENABLED:
13
+ from sqlalchemy import create_engine
14
+ from sqlalchemy.orm import DeclarativeBase, sessionmaker
15
+
16
+ class Base(DeclarativeBase):
17
+ pass
18
+ else:
19
+ Base = None
20
+
21
+
22
+ def get_db_engine():
23
+ if METADATA_ENABLED:
24
+ database_url = os.environ.get("DATABASE_URL")
25
+ if not database_url:
26
+ raise RuntimeError(
27
+ "DATABASE_URL must be set when STRATUM_METADATA_ENABLED is enabled"
28
+ )
29
+ return create_engine(database_url, echo=True)
30
+ return None
31
+
32
+ def get_session_factory():
33
+ db_engine = get_db_engine()
34
+ if db_engine is not None:
35
+ return sessionmaker(bind=db_engine)
36
+ return None
37
+
38
+ def record_flush(filename, min_key, max_key, entry_count, file_size_bytes, created_at):
39
+ session_factory = get_session_factory()
40
+ if session_factory is None:
41
+ return None
42
+ session = session_factory()
43
+ from stratum.models import SSTableMeta
44
+ SSTableMetaEntry = SSTableMeta(
45
+ filename = filename,
46
+ min_key = min_key,
47
+ max_key = max_key,
48
+ entry_count = entry_count,
49
+ file_size_bytes = file_size_bytes,
50
+ created_at = created_at
51
+ )
52
+ try:
53
+ session.add(SSTableMetaEntry)
54
+ session.commit()
55
+ except Exception as e:
56
+ session.rollback()
57
+ print(f'[Metadata] record_flush failed: {e}')
58
+ finally:
59
+ session.close()
60
+
61
+ def record_compaction(status, started_at, completed_at, tombstones_dropped, input_filenames, output_fields):
62
+ session_factory = get_session_factory()
63
+ if session_factory is None:
64
+ return None
65
+ session = session_factory()
66
+ from stratum.models import SSTableMeta, CompactionJob
67
+ try:
68
+ input_rows = (
69
+ session.query(SSTableMeta)
70
+ .filter(SSTableMeta.filename.in_(input_filenames))
71
+ .all()
72
+ )
73
+ for row in input_rows:
74
+ row.is_active = False
75
+
76
+ output_row = SSTableMeta(**output_fields)
77
+ compactionJobEntry = CompactionJob(
78
+ status = status,
79
+ started_at = started_at,
80
+ completed_at = completed_at,
81
+ tombstones_dropped = tombstones_dropped,
82
+ output_sstable = output_row,
83
+ input_sstables = input_rows,)
84
+ session.add(compactionJobEntry)
85
+ session.commit()
86
+ except Exception as e:
87
+ session.rollback()
88
+ print(f'Metadata Write failed: {e}')
89
+ finally:
90
+ session.close()
stratum/engine.py ADDED
@@ -0,0 +1,220 @@
1
+ import re
2
+ from threading import RLock
3
+ from pathlib import Path
4
+ from sortedcontainers import SortedDict
5
+ from datetime import datetime, timezone
6
+ import heapq
7
+ from itertools import groupby
8
+
9
+ from stratum.memtable import MemTable
10
+ from stratum.wal import WAL
11
+ from stratum.sstable import SSTable
12
+ from stratum import db
13
+ from stratum.metrics import MetricsRegistry
14
+
15
+ class Engine:
16
+ def __init__(self, data_dir, table_dir=None):
17
+ if not isinstance(data_dir, Path):
18
+ raise TypeError(
19
+ f"WAL requires a pathlib.Path, got {type(data_dir).__name__}. "
20
+ f"Wrap it with Path(...) at the call site."
21
+ )
22
+ if table_dir is None:
23
+ table_dir = data_dir
24
+ if not isinstance(table_dir, Path):
25
+ raise TypeError(
26
+ f"SSTable requires a pathlib.Path, got {type(table_dir).__name__}. "
27
+ f"Wrap it with Path(...) at the call site."
28
+ )
29
+
30
+ self.data_dir = data_dir
31
+ self.table_dir = table_dir
32
+ self.data_dir.mkdir(parents=True, exist_ok=True)
33
+ self.table_dir.mkdir(parents=True, exist_ok=True)
34
+
35
+ self.memtable = MemTable()
36
+ self.wal = WAL(self.data_dir)
37
+ self._seq_no = 0
38
+ self.lock = RLock()
39
+ self.sstables = []
40
+ self.tableCount = 0
41
+ self.metrics = MetricsRegistry()
42
+
43
+ self._load_sstables()
44
+ self._recover()
45
+ self._update_metrics()
46
+
47
+ def _update_metrics(self):
48
+ self.metrics.set_gauge("sstables", len(self.sstables))
49
+ self.metrics.set_gauge("memtable_entries", len(self.memtable.items()))
50
+
51
+ def _load_sstables(self):
52
+ for sst_path in sorted(self.table_dir.glob("*.sst")):
53
+ idx_path = sst_path.with_suffix('.idx')
54
+ if not idx_path.exists():
55
+ raise FileNotFoundError(f"Could not find {idx_path}")
56
+ self.sstables.append(SSTable.from_file(sst_path, idx_path))
57
+ match = re.match(r"^(\d+)", sst_path.name)
58
+ if match:
59
+ self.tableCount = max(self.tableCount, int(match.group(1)) + 1)
60
+
61
+ def _recover(self):
62
+ for seq_no, op_type, key, value in self.wal.replay():
63
+ self._seq_no = seq_no
64
+ if op_type == 1:
65
+ self.memtable.put(key, value, self._seq_no)
66
+ else:
67
+ self.memtable.delete(key, self._seq_no)
68
+
69
+ def put(self, key, value):
70
+ self.metrics.increment("puts_total")
71
+ with self.lock:
72
+ if self.memtable.is_full():
73
+ self.write_table()
74
+ self._seq_no += 1
75
+ self.wal.append(self._seq_no, 1, key, value)
76
+ self.memtable.put(key, value, self._seq_no)
77
+ self._update_metrics()
78
+
79
+ def write_table(self):
80
+ data = self.memtable.items()
81
+ self.tableCount += 1
82
+ new_sstable = SSTable.flush(self.table_dir, self.tableCount, data)
83
+ if db.METADATA_ENABLED:
84
+ created_at = datetime.now(timezone.utc)
85
+ db.record_flush(
86
+ filename=new_sstable.sst_path.name,
87
+ min_key=new_sstable.min_key,
88
+ max_key=new_sstable.max_key,
89
+ entry_count=new_sstable.entry_count,
90
+ file_size_bytes=new_sstable.file_size_bytes,
91
+ created_at=created_at
92
+ )
93
+ self.sstables.append(new_sstable)
94
+ self.wal.truncate()
95
+ self.memtable = MemTable()
96
+ self.metrics.increment("flushes_total")
97
+ self._update_metrics()
98
+
99
+ def delete(self, key):
100
+ self.metrics.increment("deletes_total")
101
+ with self.lock:
102
+ self._seq_no += 1
103
+ self.wal.append(self._seq_no, 2, key, b"")
104
+ self.memtable.delete(key,self._seq_no)
105
+ self._update_metrics()
106
+
107
+ def get(self, key):
108
+ self.metrics.increment("gets_total")
109
+ with self.lock:
110
+ record = self.memtable.get_record(key)
111
+ if record is not None:
112
+ value, _, deleted = record
113
+ return None if deleted else value
114
+
115
+ for sstable in reversed(self.sstables):
116
+ if sstable.min_key is not None and not (sstable.min_key <= key <= sstable.max_key):
117
+ continue
118
+ if not sstable.might_contain(key):
119
+ continue
120
+ results = sstable.search(key)
121
+ if results:
122
+ _, value, _, deleted = results[0]
123
+ return None if deleted else value
124
+
125
+ return None
126
+
127
+ def scan(self, start_key, end_key):
128
+ self.metrics.increment("scans_total")
129
+ if start_key > end_key:
130
+ return
131
+
132
+ with self.lock:
133
+ sstables = list(self.sstables)
134
+ memtable_items = self.memtable.items()
135
+
136
+ sources = []
137
+
138
+ for table in sstables:
139
+ if table.entry_count == 0:
140
+ continue
141
+
142
+ if table.max_key < start_key or table.min_key > end_key:
143
+ continue
144
+
145
+ sources.append(table.scan(start_key, end_key))
146
+
147
+ sources.append(
148
+ (key, value, seq_no, deleted) for key, (value, seq_no, deleted) in memtable_items if start_key <= key <= end_key
149
+ )
150
+
151
+ merged = heapq.merge(*sources, key = lambda entry: entry [0])
152
+
153
+ for key, entries in groupby(merged, key= lambda entry: entry[0]):
154
+ newest = max(entries, key = lambda entry: entry[2])
155
+ if not newest[3]:
156
+ yield key, newest[1]
157
+
158
+ def compact(self):
159
+ self.metrics.increment("compactions_total")
160
+ with self.lock:
161
+ started_at = datetime.now(timezone.utc)
162
+ entries = SortedDict()
163
+ input_filenames = []
164
+ for table in self.sstables:
165
+ input_filenames.append(table.sst_path.name)
166
+ table_entries = table.scan(table.min_key, table.max_key)
167
+ for key, val, seq_no, deleted in table_entries:
168
+ old = entries.get(key)
169
+ if old is None:
170
+ entries[key] = (val, seq_no, deleted)
171
+ else:
172
+ if seq_no > entries[key][1]:
173
+ entries[key] = (val, seq_no, deleted)
174
+ del_keys = []
175
+ for key, entry in entries.items():
176
+ if entry[2]:
177
+ del_keys.append(key)
178
+ for key in del_keys:
179
+ del entries[key]
180
+
181
+ self.tableCount += 1
182
+ created_at = datetime.now(timezone.utc)
183
+ new_table = SSTable.flush(self.table_dir, self.tableCount, entries.items())
184
+
185
+
186
+
187
+ if new_table.min_key is None:
188
+ new_table.min_key = b""
189
+ new_table.max_key = b""
190
+
191
+ old_sst_paths = [t.sst_path for t in self.sstables]
192
+ old_idx_paths = [t.idx_path for t in self.sstables]
193
+ self.sstables = [new_table]
194
+ output_fields = {
195
+ 'filename':new_table.sst_path.name,
196
+ 'min_key':new_table.min_key,
197
+ 'max_key':new_table.max_key,
198
+ 'entry_count':new_table.entry_count,
199
+ 'file_size_bytes':new_table.file_size_bytes,
200
+ 'created_at':created_at
201
+ }
202
+ if db.METADATA_ENABLED:
203
+ completed_at = datetime.now(timezone.utc)
204
+ db.record_compaction(
205
+ status="Completed",
206
+ started_at=started_at,
207
+ completed_at=completed_at,
208
+ tombstones_dropped=len(del_keys),
209
+ input_filenames=input_filenames,
210
+ output_fields=output_fields
211
+ )
212
+ for sst_path, idx_path in zip(old_sst_paths,old_idx_paths):
213
+ try:
214
+ Path(sst_path).unlink()
215
+ except OSError as e:
216
+ print(f"Failed to delete {sst_path}: {e}")
217
+ try:
218
+ Path(idx_path).unlink()
219
+ except OSError as e:
220
+ print(f"Failed to delete {idx_path}: {e}")
File without changes
stratum/grpc/server.py ADDED
@@ -0,0 +1,45 @@
1
+ from concurrent import futures
2
+ from pathlib import Path
3
+ import grpc
4
+
5
+ from stratum.grpc import stratum_pb2,stratum_pb2_grpc
6
+ from stratum.engine import Engine
7
+
8
+ class StratumServicer(stratum_pb2_grpc.StratumServicer):
9
+ def __init__(self, engine):
10
+ self.engine = engine
11
+
12
+ @staticmethod
13
+ def _require_key(key, context, field_name):
14
+ if not key:
15
+ context.abort(
16
+ grpc.StatusCode.INVALID_ARGUMENT,
17
+ f"{field_name} must not be empty",
18
+ )
19
+
20
+ def Get(self, request, context):
21
+ self._require_key(request.key, context, "key")
22
+ value = self.engine.get(request.key)
23
+ if value is None:
24
+ return stratum_pb2.GetResponse(found = False)
25
+ return stratum_pb2.GetResponse(value=value, found=True)
26
+
27
+ def Put(self, request, context):
28
+ self._require_key(request.key, context, "key")
29
+ self.engine.put(request.key, request.value)
30
+ return stratum_pb2.PutResponse(success=True)
31
+
32
+ def Scan(self, request, context):
33
+ self._require_key(request.start_key, context, "start_key")
34
+ self._require_key(request.end_key, context, "end_key")
35
+ for key, value in self.engine.scan(request.start_key, request.end_key):
36
+ yield stratum_pb2.KVPair(key=key, value=value)
37
+
38
+ def serve(data_dir, table_dir=None, port=50051):
39
+ engine = Engine(data_dir = data_dir, table_dir= table_dir)
40
+ server = grpc.server(futures.ThreadPoolExecutor(max_workers=4))
41
+ stratum_pb2_grpc.add_StratumServicer_to_server(StratumServicer(engine), server)
42
+ server.add_insecure_port(f'[::]:{port}')
43
+ server.start()
44
+ print(f"gRPC server running on port {port}")
45
+ server.wait_for_termination()
@@ -0,0 +1,48 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
3
+ # NO CHECKED-IN PROTOBUF GENCODE
4
+ # source: stratum.proto
5
+ # Protobuf Python Version: 7.35.1
6
+ """Generated protocol buffer code."""
7
+ from google.protobuf import descriptor as _descriptor
8
+ from google.protobuf import descriptor_pool as _descriptor_pool
9
+ from google.protobuf import runtime_version as _runtime_version
10
+ from google.protobuf import symbol_database as _symbol_database
11
+ from google.protobuf.internal import builder as _builder
12
+ _runtime_version.ValidateProtobufRuntimeVersion(
13
+ _runtime_version.Domain.PUBLIC,
14
+ 7,
15
+ 35,
16
+ 1,
17
+ '',
18
+ 'stratum.proto'
19
+ )
20
+ # @@protoc_insertion_point(imports)
21
+
22
+ _sym_db = _symbol_database.Default()
23
+
24
+
25
+
26
+
27
+ DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\rstratum.proto\x12\x07stratum\"\x19\n\nGetRequest\x12\x0b\n\x03key\x18\x01 \x01(\x0c\"+\n\x0bGetResponse\x12\r\n\x05value\x18\x01 \x01(\x0c\x12\r\n\x05\x66ound\x18\x02 \x01(\x08\"(\n\nPutRequest\x12\x0b\n\x03key\x18\x01 \x01(\x0c\x12\r\n\x05value\x18\x02 \x01(\x0c\"\x1e\n\x0bPutResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\"1\n\x0bScanRequest\x12\x11\n\tstart_key\x18\x01 \x01(\x0c\x12\x0f\n\x07\x65nd_key\x18\x02 \x01(\x0c\"$\n\x06KVPair\x12\x0b\n\x03key\x18\x01 \x01(\x0c\x12\r\n\x05value\x18\x02 \x01(\x0c\x32\x9e\x01\n\x07Stratum\x12\x30\n\x03Get\x12\x13.stratum.GetRequest\x1a\x14.stratum.GetResponse\x12\x30\n\x03Put\x12\x13.stratum.PutRequest\x1a\x14.stratum.PutResponse\x12/\n\x04Scan\x12\x14.stratum.ScanRequest\x1a\x0f.stratum.KVPair0\x01\x62\x06proto3')
28
+
29
+ _globals = globals()
30
+ _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
31
+ _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'stratum_pb2', _globals)
32
+ if not _descriptor._USE_C_DESCRIPTORS:
33
+ DESCRIPTOR._loaded_options = None
34
+ _globals['_GETREQUEST']._serialized_start=26
35
+ _globals['_GETREQUEST']._serialized_end=51
36
+ _globals['_GETRESPONSE']._serialized_start=53
37
+ _globals['_GETRESPONSE']._serialized_end=96
38
+ _globals['_PUTREQUEST']._serialized_start=98
39
+ _globals['_PUTREQUEST']._serialized_end=138
40
+ _globals['_PUTRESPONSE']._serialized_start=140
41
+ _globals['_PUTRESPONSE']._serialized_end=170
42
+ _globals['_SCANREQUEST']._serialized_start=172
43
+ _globals['_SCANREQUEST']._serialized_end=221
44
+ _globals['_KVPAIR']._serialized_start=223
45
+ _globals['_KVPAIR']._serialized_end=259
46
+ _globals['_STRATUM']._serialized_start=262
47
+ _globals['_STRATUM']._serialized_end=420
48
+ # @@protoc_insertion_point(module_scope)
@@ -0,0 +1,183 @@
1
+ # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
2
+ """Client and server classes corresponding to protobuf-defined services."""
3
+ import grpc
4
+ import warnings
5
+
6
+ from . import stratum_pb2 as stratum__pb2
7
+
8
+ GRPC_GENERATED_VERSION = '1.83.1'
9
+ GRPC_VERSION = grpc.__version__
10
+ _version_not_supported = False
11
+
12
+ try:
13
+ from grpc._utilities import first_version_is_lower
14
+ _version_not_supported = first_version_is_lower(GRPC_VERSION, GRPC_GENERATED_VERSION)
15
+ except ImportError:
16
+ _version_not_supported = True
17
+
18
+ if _version_not_supported:
19
+ raise RuntimeError(
20
+ f'The grpc package installed is at version {GRPC_VERSION},'
21
+ + ' but the generated code in stratum_pb2_grpc.py depends on'
22
+ + f' grpcio>={GRPC_GENERATED_VERSION}.'
23
+ + f' Please upgrade your grpc module to grpcio>={GRPC_GENERATED_VERSION}'
24
+ + f' or downgrade your generated code using grpcio-tools<={GRPC_VERSION}.'
25
+ )
26
+
27
+
28
+ class StratumStub:
29
+ """Missing associated documentation comment in .proto file."""
30
+
31
+ def __init__(self, channel):
32
+ """Constructor.
33
+
34
+ Args:
35
+ channel: A grpc.Channel.
36
+ """
37
+ self.Get = channel.unary_unary(
38
+ '/stratum.Stratum/Get',
39
+ request_serializer=stratum__pb2.GetRequest.SerializeToString,
40
+ response_deserializer=stratum__pb2.GetResponse.FromString,
41
+ _registered_method=True)
42
+ self.Put = channel.unary_unary(
43
+ '/stratum.Stratum/Put',
44
+ request_serializer=stratum__pb2.PutRequest.SerializeToString,
45
+ response_deserializer=stratum__pb2.PutResponse.FromString,
46
+ _registered_method=True)
47
+ self.Scan = channel.unary_stream(
48
+ '/stratum.Stratum/Scan',
49
+ request_serializer=stratum__pb2.ScanRequest.SerializeToString,
50
+ response_deserializer=stratum__pb2.KVPair.FromString,
51
+ _registered_method=True)
52
+
53
+
54
+ class StratumServicer:
55
+ """Missing associated documentation comment in .proto file."""
56
+
57
+ def Get(self, request, context):
58
+ """Missing associated documentation comment in .proto file."""
59
+ context.set_code(grpc.StatusCode.UNIMPLEMENTED)
60
+ context.set_details('Method not implemented!')
61
+ raise NotImplementedError('Method not implemented!')
62
+
63
+ def Put(self, request, context):
64
+ """Missing associated documentation comment in .proto file."""
65
+ context.set_code(grpc.StatusCode.UNIMPLEMENTED)
66
+ context.set_details('Method not implemented!')
67
+ raise NotImplementedError('Method not implemented!')
68
+
69
+ def Scan(self, request, context):
70
+ """Missing associated documentation comment in .proto file."""
71
+ context.set_code(grpc.StatusCode.UNIMPLEMENTED)
72
+ context.set_details('Method not implemented!')
73
+ raise NotImplementedError('Method not implemented!')
74
+
75
+
76
+ def add_StratumServicer_to_server(servicer, server):
77
+ rpc_method_handlers = {
78
+ 'Get': grpc.unary_unary_rpc_method_handler(
79
+ servicer.Get,
80
+ request_deserializer=stratum__pb2.GetRequest.FromString,
81
+ response_serializer=stratum__pb2.GetResponse.SerializeToString,
82
+ ),
83
+ 'Put': grpc.unary_unary_rpc_method_handler(
84
+ servicer.Put,
85
+ request_deserializer=stratum__pb2.PutRequest.FromString,
86
+ response_serializer=stratum__pb2.PutResponse.SerializeToString,
87
+ ),
88
+ 'Scan': grpc.unary_stream_rpc_method_handler(
89
+ servicer.Scan,
90
+ request_deserializer=stratum__pb2.ScanRequest.FromString,
91
+ response_serializer=stratum__pb2.KVPair.SerializeToString,
92
+ ),
93
+ }
94
+ generic_handler = grpc.method_handlers_generic_handler(
95
+ 'stratum.Stratum', rpc_method_handlers)
96
+ server.add_generic_rpc_handlers((generic_handler,))
97
+ server.add_registered_method_handlers('stratum.Stratum', rpc_method_handlers)
98
+
99
+
100
+ # This class is part of an EXPERIMENTAL API.
101
+ class Stratum:
102
+ """Missing associated documentation comment in .proto file."""
103
+
104
+ @staticmethod
105
+ def Get(request,
106
+ target,
107
+ options=(),
108
+ channel_credentials=None,
109
+ call_credentials=None,
110
+ insecure=False,
111
+ compression=None,
112
+ wait_for_ready=None,
113
+ timeout=None,
114
+ metadata=None):
115
+ return grpc.experimental.unary_unary(
116
+ request,
117
+ target,
118
+ '/stratum.Stratum/Get',
119
+ stratum__pb2.GetRequest.SerializeToString,
120
+ stratum__pb2.GetResponse.FromString,
121
+ options,
122
+ channel_credentials,
123
+ insecure,
124
+ call_credentials,
125
+ compression,
126
+ wait_for_ready,
127
+ timeout,
128
+ metadata,
129
+ _registered_method=True)
130
+
131
+ @staticmethod
132
+ def Put(request,
133
+ target,
134
+ options=(),
135
+ channel_credentials=None,
136
+ call_credentials=None,
137
+ insecure=False,
138
+ compression=None,
139
+ wait_for_ready=None,
140
+ timeout=None,
141
+ metadata=None):
142
+ return grpc.experimental.unary_unary(
143
+ request,
144
+ target,
145
+ '/stratum.Stratum/Put',
146
+ stratum__pb2.PutRequest.SerializeToString,
147
+ stratum__pb2.PutResponse.FromString,
148
+ options,
149
+ channel_credentials,
150
+ insecure,
151
+ call_credentials,
152
+ compression,
153
+ wait_for_ready,
154
+ timeout,
155
+ metadata,
156
+ _registered_method=True)
157
+
158
+ @staticmethod
159
+ def Scan(request,
160
+ target,
161
+ options=(),
162
+ channel_credentials=None,
163
+ call_credentials=None,
164
+ insecure=False,
165
+ compression=None,
166
+ wait_for_ready=None,
167
+ timeout=None,
168
+ metadata=None):
169
+ return grpc.experimental.unary_stream(
170
+ request,
171
+ target,
172
+ '/stratum.Stratum/Scan',
173
+ stratum__pb2.ScanRequest.SerializeToString,
174
+ stratum__pb2.KVPair.FromString,
175
+ options,
176
+ channel_credentials,
177
+ insecure,
178
+ call_credentials,
179
+ compression,
180
+ wait_for_ready,
181
+ timeout,
182
+ metadata,
183
+ _registered_method=True)
stratum/init_db.py ADDED
@@ -0,0 +1,6 @@
1
+ from stratum.db import Base, get_session_factory, get_db_engine
2
+ from stratum.models import SSTableMeta, CompactionJob
3
+
4
+ database_engine = get_db_engine()
5
+ Base.metadata.create_all(database_engine)
6
+ print("Database initialized")