nucliadb 6.2.1.post2971__py3-none-any.whl → 6.2.1.post2972__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.
- nucliadb/common/cluster/manager.py +33 -331
- nucliadb/common/cluster/rebalance.py +2 -2
- nucliadb/common/cluster/rollover.py +12 -71
- nucliadb/common/cluster/standalone/utils.py +0 -43
- nucliadb/common/cluster/utils.py +0 -16
- nucliadb/common/nidx.py +21 -23
- nucliadb/health.py +0 -7
- nucliadb/ingest/app.py +0 -8
- nucliadb/ingest/consumer/auditing.py +1 -1
- nucliadb/ingest/consumer/shard_creator.py +1 -1
- nucliadb/ingest/orm/entities.py +3 -6
- nucliadb/purge/orphan_shards.py +6 -4
- nucliadb/search/api/v1/knowledgebox.py +1 -5
- nucliadb/search/requesters/utils.py +1 -2
- nucliadb/search/search/shards.py +19 -0
- nucliadb/standalone/introspect.py +0 -25
- nucliadb/train/lifecycle.py +0 -6
- nucliadb/train/nodes.py +1 -5
- nucliadb/writer/back_pressure.py +17 -46
- nucliadb/writer/settings.py +2 -2
- {nucliadb-6.2.1.post2971.dist-info → nucliadb-6.2.1.post2972.dist-info}/METADATA +5 -7
- {nucliadb-6.2.1.post2971.dist-info → nucliadb-6.2.1.post2972.dist-info}/RECORD +26 -36
- nucliadb/common/cluster/discovery/__init__.py +0 -19
- nucliadb/common/cluster/discovery/base.py +0 -178
- nucliadb/common/cluster/discovery/k8s.py +0 -301
- nucliadb/common/cluster/discovery/manual.py +0 -57
- nucliadb/common/cluster/discovery/single.py +0 -51
- nucliadb/common/cluster/discovery/types.py +0 -32
- nucliadb/common/cluster/discovery/utils.py +0 -67
- nucliadb/common/cluster/standalone/grpc_node_binding.py +0 -349
- nucliadb/common/cluster/standalone/index_node.py +0 -123
- nucliadb/common/cluster/standalone/service.py +0 -84
- {nucliadb-6.2.1.post2971.dist-info → nucliadb-6.2.1.post2972.dist-info}/WHEEL +0 -0
- {nucliadb-6.2.1.post2971.dist-info → nucliadb-6.2.1.post2972.dist-info}/entry_points.txt +0 -0
- {nucliadb-6.2.1.post2971.dist-info → nucliadb-6.2.1.post2972.dist-info}/top_level.txt +0 -0
- {nucliadb-6.2.1.post2971.dist-info → nucliadb-6.2.1.post2972.dist-info}/zip-safe +0 -0
@@ -1,349 +0,0 @@
|
|
1
|
-
# Copyright (C) 2021 Bosutech XXI S.L.
|
2
|
-
#
|
3
|
-
# nucliadb is offered under the AGPL v3.0 and as commercial software.
|
4
|
-
# For commercial licensing, contact us at info@nuclia.com.
|
5
|
-
#
|
6
|
-
# AGPL:
|
7
|
-
# This program is free software: you can redistribute it and/or modify
|
8
|
-
# it under the terms of the GNU Affero General Public License as
|
9
|
-
# published by the Free Software Foundation, either version 3 of the
|
10
|
-
# License, or (at your option) any later version.
|
11
|
-
#
|
12
|
-
# This program is distributed in the hope that it will be useful,
|
13
|
-
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
-
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
-
# GNU Affero General Public License for more details.
|
16
|
-
#
|
17
|
-
# You should have received a copy of the GNU Affero General Public License
|
18
|
-
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
19
|
-
#
|
20
|
-
from __future__ import annotations
|
21
|
-
|
22
|
-
import asyncio
|
23
|
-
import logging
|
24
|
-
import os
|
25
|
-
import threading
|
26
|
-
from concurrent.futures import ThreadPoolExecutor
|
27
|
-
from typing import AsyncIterator
|
28
|
-
|
29
|
-
from nucliadb_protos.nodereader_pb2 import (
|
30
|
-
DocumentItem,
|
31
|
-
EdgeList,
|
32
|
-
GetShardRequest,
|
33
|
-
IdCollection,
|
34
|
-
ParagraphItem,
|
35
|
-
ParagraphSearchRequest,
|
36
|
-
ParagraphSearchResponse,
|
37
|
-
RelationSearchRequest,
|
38
|
-
RelationSearchResponse,
|
39
|
-
SearchRequest,
|
40
|
-
SearchResponse,
|
41
|
-
StreamRequest,
|
42
|
-
SuggestRequest,
|
43
|
-
SuggestResponse,
|
44
|
-
)
|
45
|
-
from nucliadb_protos.noderesources_pb2 import (
|
46
|
-
EmptyQuery,
|
47
|
-
EmptyResponse,
|
48
|
-
Resource,
|
49
|
-
ResourceID,
|
50
|
-
ShardCreated,
|
51
|
-
ShardId,
|
52
|
-
ShardIds,
|
53
|
-
VectorSetID,
|
54
|
-
VectorSetList,
|
55
|
-
)
|
56
|
-
from nucliadb_protos.noderesources_pb2 import Shard as NodeResourcesShard
|
57
|
-
from nucliadb_protos.nodewriter_pb2 import NewShardRequest, OpStatus
|
58
|
-
|
59
|
-
from ..settings import settings
|
60
|
-
|
61
|
-
logger = logging.getLogger(__name__)
|
62
|
-
|
63
|
-
try:
|
64
|
-
from nucliadb_node_binding import IndexNodeException # type: ignore
|
65
|
-
except ImportError: # pragma: no cover
|
66
|
-
logger.warning("Import error while importing IndexNodeException")
|
67
|
-
IndexNodeException = Exception
|
68
|
-
|
69
|
-
try:
|
70
|
-
from nucliadb_node_binding import NodeReader, NodeWriter
|
71
|
-
except ImportError: # pragma: no cover
|
72
|
-
NodeReader = None
|
73
|
-
NodeWriter = None
|
74
|
-
|
75
|
-
|
76
|
-
class StandaloneReaderWrapper:
|
77
|
-
reader: NodeReader
|
78
|
-
|
79
|
-
def __init__(self):
|
80
|
-
if NodeReader is None:
|
81
|
-
raise ImportError("NucliaDB index node bindings are not installed (reader not found)")
|
82
|
-
self.reader = NodeReader()
|
83
|
-
self.executor = ThreadPoolExecutor(settings.local_reader_threads)
|
84
|
-
|
85
|
-
async def Search(self, request: SearchRequest, retry: bool = False) -> SearchResponse:
|
86
|
-
try:
|
87
|
-
loop = asyncio.get_running_loop()
|
88
|
-
result = await loop.run_in_executor(
|
89
|
-
self.executor, self.reader.search, request.SerializeToString()
|
90
|
-
)
|
91
|
-
pb_bytes = bytes(result)
|
92
|
-
pb = SearchResponse()
|
93
|
-
pb.ParseFromString(pb_bytes)
|
94
|
-
return pb
|
95
|
-
except IndexNodeException as exc:
|
96
|
-
if "IO error" not in str(exc):
|
97
|
-
# ignore any other error
|
98
|
-
raise
|
99
|
-
|
100
|
-
# try some mitigations...
|
101
|
-
logger.error(f"IndexNodeException in Search: {request}", exc_info=True)
|
102
|
-
if not retry:
|
103
|
-
# reinit?
|
104
|
-
self.reader = NodeReader()
|
105
|
-
return await self.Search(request, retry=True)
|
106
|
-
else:
|
107
|
-
raise
|
108
|
-
|
109
|
-
async def GetShard(self, request: GetShardRequest) -> NodeResourcesShard:
|
110
|
-
loop = asyncio.get_running_loop()
|
111
|
-
result = await loop.run_in_executor(
|
112
|
-
self.executor, self.reader.get_shard, request.SerializeToString()
|
113
|
-
)
|
114
|
-
pb_bytes = bytes(result)
|
115
|
-
shard = NodeResourcesShard()
|
116
|
-
shard.ParseFromString(pb_bytes)
|
117
|
-
return shard
|
118
|
-
|
119
|
-
async def Suggest(self, request: SuggestRequest) -> SuggestResponse:
|
120
|
-
loop = asyncio.get_running_loop()
|
121
|
-
result = await loop.run_in_executor(
|
122
|
-
self.executor, self.reader.suggest, request.SerializeToString()
|
123
|
-
)
|
124
|
-
pb_bytes = bytes(result)
|
125
|
-
pb = SuggestResponse()
|
126
|
-
pb.ParseFromString(pb_bytes)
|
127
|
-
return pb
|
128
|
-
|
129
|
-
async def Documents(
|
130
|
-
self, stream_request: StreamRequest
|
131
|
-
) -> AsyncIterator[DocumentItem]: # pragma: no cover
|
132
|
-
"""
|
133
|
-
This is a workaround for the fact that the node binding does not support async generators.
|
134
|
-
|
135
|
-
Very difficult to write tests for
|
136
|
-
"""
|
137
|
-
loop = asyncio.get_running_loop()
|
138
|
-
q: asyncio.Queue[DocumentItem] = asyncio.Queue(1)
|
139
|
-
exception = None
|
140
|
-
_END = object()
|
141
|
-
|
142
|
-
def thread_generator():
|
143
|
-
nonlocal exception
|
144
|
-
generator = self.reader.documents(stream_request.SerializeToString())
|
145
|
-
try:
|
146
|
-
element = generator.next()
|
147
|
-
while element is not None:
|
148
|
-
pb_bytes = bytes(element)
|
149
|
-
pb = DocumentItem()
|
150
|
-
pb.ParseFromString(pb_bytes)
|
151
|
-
asyncio.run_coroutine_threadsafe(q.put(pb), loop).result()
|
152
|
-
element = generator.next()
|
153
|
-
except StopIteration:
|
154
|
-
# this is the end
|
155
|
-
pass
|
156
|
-
except Exception as e:
|
157
|
-
exception = e
|
158
|
-
finally:
|
159
|
-
asyncio.run_coroutine_threadsafe(q.put(_END), loop).result()
|
160
|
-
|
161
|
-
t1 = threading.Thread(target=thread_generator)
|
162
|
-
t1.start()
|
163
|
-
|
164
|
-
while True:
|
165
|
-
next_item = await q.get()
|
166
|
-
if next_item is _END:
|
167
|
-
break
|
168
|
-
yield next_item
|
169
|
-
if exception is not None:
|
170
|
-
raise exception
|
171
|
-
await loop.run_in_executor(self.executor, t1.join)
|
172
|
-
|
173
|
-
async def Paragraphs(self, stream_request: StreamRequest) -> AsyncIterator[ParagraphItem]:
|
174
|
-
loop = asyncio.get_running_loop()
|
175
|
-
q: asyncio.Queue[ParagraphItem] = asyncio.Queue(1)
|
176
|
-
exception = None
|
177
|
-
_END = object()
|
178
|
-
|
179
|
-
def thread_generator():
|
180
|
-
nonlocal exception
|
181
|
-
generator = self.reader.paragraphs(stream_request.SerializeToString())
|
182
|
-
try:
|
183
|
-
element = generator.next()
|
184
|
-
while element is not None:
|
185
|
-
pb_bytes = bytes(element)
|
186
|
-
pb = ParagraphItem()
|
187
|
-
pb.ParseFromString(pb_bytes)
|
188
|
-
asyncio.run_coroutine_threadsafe(q.put(pb), loop).result()
|
189
|
-
element = generator.next()
|
190
|
-
except StopIteration:
|
191
|
-
# this is the end
|
192
|
-
pass
|
193
|
-
except Exception as e:
|
194
|
-
exception = e
|
195
|
-
finally:
|
196
|
-
asyncio.run_coroutine_threadsafe(q.put(_END), loop).result()
|
197
|
-
|
198
|
-
t1 = threading.Thread(target=thread_generator)
|
199
|
-
t1.start()
|
200
|
-
while True:
|
201
|
-
next_item = await q.get()
|
202
|
-
if next_item is _END:
|
203
|
-
break
|
204
|
-
yield next_item
|
205
|
-
if exception is not None:
|
206
|
-
raise exception
|
207
|
-
await loop.run_in_executor(self.executor, t1.join)
|
208
|
-
|
209
|
-
async def RelationEdges(self, request: ShardId):
|
210
|
-
loop = asyncio.get_running_loop()
|
211
|
-
result = await loop.run_in_executor(
|
212
|
-
self.executor, self.reader.relation_edges, request.SerializeToString()
|
213
|
-
)
|
214
|
-
pb_bytes = bytes(result)
|
215
|
-
edge_list = EdgeList()
|
216
|
-
edge_list.ParseFromString(pb_bytes)
|
217
|
-
return edge_list
|
218
|
-
|
219
|
-
async def VectorIds(self, request: VectorSetID) -> IdCollection:
|
220
|
-
loop = asyncio.get_running_loop()
|
221
|
-
result = await loop.run_in_executor(
|
222
|
-
self.executor, self.reader.vector_ids, request.SerializeToString()
|
223
|
-
)
|
224
|
-
pb_bytes = bytes(result)
|
225
|
-
ids = IdCollection()
|
226
|
-
ids.ParseFromString(pb_bytes)
|
227
|
-
return ids
|
228
|
-
|
229
|
-
|
230
|
-
class StandaloneWriterWrapper:
|
231
|
-
writer: NodeWriter
|
232
|
-
|
233
|
-
def __init__(self):
|
234
|
-
os.makedirs(settings.data_path, exist_ok=True)
|
235
|
-
if NodeWriter is None:
|
236
|
-
raise ImportError("NucliaDB index node bindings are not installed (writer not found)")
|
237
|
-
self.writer = NodeWriter()
|
238
|
-
self.executor = ThreadPoolExecutor(settings.local_writer_threads)
|
239
|
-
|
240
|
-
async def NewShard(self, request: NewShardRequest) -> ShardCreated:
|
241
|
-
loop = asyncio.get_running_loop()
|
242
|
-
resp = await loop.run_in_executor(
|
243
|
-
self.executor, self.writer.new_shard, request.SerializeToString()
|
244
|
-
)
|
245
|
-
pb_bytes = bytes(resp)
|
246
|
-
shard_created = ShardCreated()
|
247
|
-
shard_created.ParseFromString(pb_bytes)
|
248
|
-
return shard_created
|
249
|
-
|
250
|
-
async def DeleteShard(self, request: ShardId) -> ShardId:
|
251
|
-
loop = asyncio.get_running_loop()
|
252
|
-
resp = await loop.run_in_executor(
|
253
|
-
self.executor, self.writer.delete_shard, request.SerializeToString()
|
254
|
-
)
|
255
|
-
pb_bytes = bytes(resp)
|
256
|
-
shard_id = ShardId()
|
257
|
-
shard_id.ParseFromString(pb_bytes)
|
258
|
-
return shard_id
|
259
|
-
|
260
|
-
async def ListShards(self, request: EmptyQuery) -> ShardIds:
|
261
|
-
loop = asyncio.get_running_loop()
|
262
|
-
resp = await loop.run_in_executor(
|
263
|
-
self.executor,
|
264
|
-
self.writer.list_shards,
|
265
|
-
)
|
266
|
-
pb_bytes = bytes(resp)
|
267
|
-
shard_ids = ShardIds()
|
268
|
-
shard_ids.ParseFromString(pb_bytes)
|
269
|
-
return shard_ids
|
270
|
-
|
271
|
-
async def AddVectorSet(self, request: VectorSetID):
|
272
|
-
loop = asyncio.get_running_loop()
|
273
|
-
resp = await loop.run_in_executor(
|
274
|
-
self.executor, self.writer.add_vectorset, request.SerializeToString()
|
275
|
-
)
|
276
|
-
pb_bytes = bytes(resp)
|
277
|
-
resp = OpStatus()
|
278
|
-
resp.ParseFromString(pb_bytes)
|
279
|
-
return resp
|
280
|
-
|
281
|
-
async def ListVectorSets(self, request: ShardId):
|
282
|
-
loop = asyncio.get_running_loop()
|
283
|
-
resp = await loop.run_in_executor(
|
284
|
-
self.executor, self.writer.list_vectorsets, request.SerializeToString()
|
285
|
-
)
|
286
|
-
pb_bytes = bytes(resp)
|
287
|
-
resp = VectorSetList()
|
288
|
-
resp.ParseFromString(pb_bytes)
|
289
|
-
return resp
|
290
|
-
|
291
|
-
async def RemoveVectorSet(self, request: VectorSetID):
|
292
|
-
loop = asyncio.get_running_loop()
|
293
|
-
resp = await loop.run_in_executor(
|
294
|
-
self.executor, self.writer.remove_vectorset, request.SerializeToString()
|
295
|
-
)
|
296
|
-
pb_bytes = bytes(resp)
|
297
|
-
resp = OpStatus()
|
298
|
-
resp.ParseFromString(pb_bytes)
|
299
|
-
return resp
|
300
|
-
|
301
|
-
async def SetResource(self, request: Resource) -> OpStatus:
|
302
|
-
loop = asyncio.get_running_loop()
|
303
|
-
resp = await loop.run_in_executor(
|
304
|
-
self.executor, self.writer.set_resource, request.SerializeToString()
|
305
|
-
)
|
306
|
-
pb_bytes = bytes(resp)
|
307
|
-
op_status = OpStatus()
|
308
|
-
op_status.ParseFromString(pb_bytes)
|
309
|
-
return op_status
|
310
|
-
|
311
|
-
async def RemoveResource(self, request: ResourceID) -> OpStatus:
|
312
|
-
loop = asyncio.get_running_loop()
|
313
|
-
resp = await loop.run_in_executor(
|
314
|
-
self.executor, self.writer.remove_resource, request.SerializeToString()
|
315
|
-
)
|
316
|
-
pb_bytes = bytes(resp)
|
317
|
-
op_status = OpStatus()
|
318
|
-
op_status.ParseFromString(pb_bytes)
|
319
|
-
return op_status
|
320
|
-
|
321
|
-
async def GC(self, request: ShardId) -> EmptyResponse:
|
322
|
-
loop = asyncio.get_running_loop()
|
323
|
-
resp = await loop.run_in_executor(self.executor, self.writer.gc, request.SerializeToString())
|
324
|
-
pb_bytes = bytes(resp)
|
325
|
-
op_status = EmptyResponse()
|
326
|
-
op_status.ParseFromString(pb_bytes)
|
327
|
-
return op_status
|
328
|
-
|
329
|
-
|
330
|
-
# supported marshalled reader methods for standalone node support
|
331
|
-
READER_METHODS = {
|
332
|
-
"Search": (SearchRequest, SearchResponse),
|
333
|
-
"ParagraphSearch": (ParagraphSearchRequest, ParagraphSearchResponse),
|
334
|
-
"RelationSearch": (RelationSearchRequest, RelationSearchResponse),
|
335
|
-
"GetShard": (GetShardRequest, NodeResourcesShard),
|
336
|
-
"Suggest": (SuggestRequest, SuggestResponse),
|
337
|
-
"RelationEdges": (ShardId, EdgeList),
|
338
|
-
}
|
339
|
-
WRITER_METHODS = {
|
340
|
-
"NewShard": (NewShardRequest, ShardCreated),
|
341
|
-
"DeleteShard": (ShardId, ShardId),
|
342
|
-
"ListShards": (EmptyQuery, ShardIds),
|
343
|
-
"RemoveVectorSet": (VectorSetID, OpStatus),
|
344
|
-
"AddVectorSet": (VectorSetID, OpStatus),
|
345
|
-
"ListVectorSets": (ShardId, VectorSetList),
|
346
|
-
"SetResource": (Resource, OpStatus),
|
347
|
-
"RemoveResource": (ResourceID, OpStatus),
|
348
|
-
"GC": (ShardId, EmptyResponse),
|
349
|
-
}
|
@@ -1,123 +0,0 @@
|
|
1
|
-
# Copyright (C) 2021 Bosutech XXI S.L.
|
2
|
-
#
|
3
|
-
# nucliadb is offered under the AGPL v3.0 and as commercial software.
|
4
|
-
# For commercial licensing, contact us at info@nuclia.com.
|
5
|
-
#
|
6
|
-
# AGPL:
|
7
|
-
# This program is free software: you can redistribute it and/or modify
|
8
|
-
# it under the terms of the GNU Affero General Public License as
|
9
|
-
# published by the Free Software Foundation, either version 3 of the
|
10
|
-
# License, or (at your option) any later version.
|
11
|
-
#
|
12
|
-
# This program is distributed in the hope that it will be useful,
|
13
|
-
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
-
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
-
# GNU Affero General Public License for more details.
|
16
|
-
#
|
17
|
-
# You should have received a copy of the GNU Affero General Public License
|
18
|
-
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
19
|
-
#
|
20
|
-
from typing import Any, Optional
|
21
|
-
|
22
|
-
from nucliadb.common.cluster.base import AbstractIndexNode
|
23
|
-
from nucliadb.common.cluster.grpc_node_dummy import DummyReaderStub, DummyWriterStub
|
24
|
-
from nucliadb.common.cluster.settings import settings as cluster_settings
|
25
|
-
from nucliadb.common.cluster.standalone import grpc_node_binding
|
26
|
-
from nucliadb_protos import standalone_pb2, standalone_pb2_grpc
|
27
|
-
from nucliadb_utils.grpc import get_traced_grpc_channel
|
28
|
-
|
29
|
-
|
30
|
-
class StandaloneIndexNode(AbstractIndexNode):
|
31
|
-
_writer: grpc_node_binding.StandaloneWriterWrapper
|
32
|
-
_reader: grpc_node_binding.StandaloneReaderWrapper
|
33
|
-
label: str = "standalone"
|
34
|
-
|
35
|
-
def __init__(
|
36
|
-
self,
|
37
|
-
id: str,
|
38
|
-
address: str,
|
39
|
-
shard_count: int,
|
40
|
-
available_disk: int,
|
41
|
-
dummy: bool = False,
|
42
|
-
primary_id: Optional[str] = None,
|
43
|
-
):
|
44
|
-
super().__init__(
|
45
|
-
id=id,
|
46
|
-
address=address,
|
47
|
-
shard_count=shard_count,
|
48
|
-
available_disk=available_disk,
|
49
|
-
dummy=dummy,
|
50
|
-
# standalone does not support read replicas
|
51
|
-
primary_id=None,
|
52
|
-
)
|
53
|
-
if dummy:
|
54
|
-
self._writer = DummyWriterStub() # type: ignore
|
55
|
-
self._reader = DummyReaderStub() # type: ignore
|
56
|
-
else:
|
57
|
-
self._writer = grpc_node_binding.StandaloneWriterWrapper()
|
58
|
-
self._reader = grpc_node_binding.StandaloneReaderWrapper()
|
59
|
-
|
60
|
-
@property
|
61
|
-
def reader(self) -> grpc_node_binding.StandaloneReaderWrapper: # type: ignore
|
62
|
-
return self._reader
|
63
|
-
|
64
|
-
@property
|
65
|
-
def writer(self) -> grpc_node_binding.StandaloneWriterWrapper: # type: ignore
|
66
|
-
return self._writer
|
67
|
-
|
68
|
-
|
69
|
-
class ProxyCallerWrapper:
|
70
|
-
def __init__(self, address: str, type: str, original_type: Any):
|
71
|
-
self._address = address
|
72
|
-
self._type = type
|
73
|
-
self._original_type = original_type
|
74
|
-
if ":" not in address:
|
75
|
-
grpc_address = f"{address}:{cluster_settings.standalone_node_port}"
|
76
|
-
else:
|
77
|
-
grpc_address = address
|
78
|
-
self._channel = get_traced_grpc_channel(grpc_address, "standalone_proxy")
|
79
|
-
self._stub = standalone_pb2_grpc.StandaloneClusterServiceStub(self._channel)
|
80
|
-
|
81
|
-
def __getattr__(self, name):
|
82
|
-
async def call(request):
|
83
|
-
req = standalone_pb2.NodeActionRequest(
|
84
|
-
service=self._type, action=name, payload=request.SerializeToString()
|
85
|
-
)
|
86
|
-
resp = await self._stub.NodeAction(req)
|
87
|
-
try:
|
88
|
-
if self._type == "reader":
|
89
|
-
_, return_type = grpc_node_binding.READER_METHODS[name]
|
90
|
-
elif self._type == "writer":
|
91
|
-
_, return_type = grpc_node_binding.WRITER_METHODS[name]
|
92
|
-
else:
|
93
|
-
raise NotImplementedError(f"Unknown type {self._type}")
|
94
|
-
except KeyError:
|
95
|
-
raise NotImplementedError(f"Unknown method for type {self._type}: {name}")
|
96
|
-
return_value = return_type()
|
97
|
-
return_value.ParseFromString(resp.payload)
|
98
|
-
return return_value
|
99
|
-
|
100
|
-
return call
|
101
|
-
|
102
|
-
|
103
|
-
class ProxyStandaloneIndexNode(StandaloneIndexNode):
|
104
|
-
label: str = "proxy_standalone"
|
105
|
-
|
106
|
-
def __init__(
|
107
|
-
self,
|
108
|
-
id: str,
|
109
|
-
address: str,
|
110
|
-
shard_count: int,
|
111
|
-
available_disk: int,
|
112
|
-
dummy: bool = False,
|
113
|
-
):
|
114
|
-
super().__init__(id, address, shard_count, available_disk=available_disk, dummy=dummy)
|
115
|
-
if dummy:
|
116
|
-
return
|
117
|
-
|
118
|
-
self._writer = ProxyCallerWrapper( # type: ignore
|
119
|
-
address, "writer", grpc_node_binding.StandaloneWriterWrapper
|
120
|
-
)
|
121
|
-
self._reader = ProxyCallerWrapper( # type: ignore
|
122
|
-
address, "reader", grpc_node_binding.StandaloneReaderWrapper
|
123
|
-
)
|
@@ -1,84 +0,0 @@
|
|
1
|
-
# Copyright (C) 2021 Bosutech XXI S.L.
|
2
|
-
#
|
3
|
-
# nucliadb is offered under the AGPL v3.0 and as commercial software.
|
4
|
-
# For commercial licensing, contact us at info@nuclia.com.
|
5
|
-
#
|
6
|
-
# AGPL:
|
7
|
-
# This program is free software: you can redistribute it and/or modify
|
8
|
-
# it under the terms of the GNU Affero General Public License as
|
9
|
-
# published by the Free Software Foundation, either version 3 of the
|
10
|
-
# License, or (at your option) any later version.
|
11
|
-
#
|
12
|
-
# This program is distributed in the hope that it will be useful,
|
13
|
-
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
-
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
-
# GNU Affero General Public License for more details.
|
16
|
-
#
|
17
|
-
# You should have received a copy of the GNU Affero General Public License
|
18
|
-
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
19
|
-
#
|
20
|
-
import os
|
21
|
-
import shutil
|
22
|
-
|
23
|
-
import backoff
|
24
|
-
from grpc import aio
|
25
|
-
from grpc.aio import AioRpcError
|
26
|
-
|
27
|
-
from nucliadb.common.cluster.settings import settings
|
28
|
-
from nucliadb.common.cluster.settings import settings as cluster_settings
|
29
|
-
from nucliadb.common.cluster.standalone import grpc_node_binding
|
30
|
-
from nucliadb.common.cluster.standalone.utils import get_self
|
31
|
-
from nucliadb_protos import standalone_pb2, standalone_pb2_grpc
|
32
|
-
from nucliadb_utils.grpc import get_traced_grpc_server
|
33
|
-
|
34
|
-
|
35
|
-
class StandaloneClusterServiceServicer(standalone_pb2_grpc.StandaloneClusterServiceServicer):
|
36
|
-
@backoff.on_exception(backoff.expo, (AioRpcError,), max_time=60)
|
37
|
-
async def NodeAction( # type: ignore
|
38
|
-
self, request: standalone_pb2.NodeActionRequest, context
|
39
|
-
) -> standalone_pb2.NodeActionResponse:
|
40
|
-
service = request.service
|
41
|
-
action = request.action
|
42
|
-
try:
|
43
|
-
if service == "reader":
|
44
|
-
request_type, _ = grpc_node_binding.READER_METHODS[action]
|
45
|
-
elif service == "writer":
|
46
|
-
request_type, _ = grpc_node_binding.WRITER_METHODS[action]
|
47
|
-
else:
|
48
|
-
raise NotImplementedError(f"Unknown type {service}")
|
49
|
-
except KeyError:
|
50
|
-
raise NotImplementedError(f"Unknown method for type {service}: {action}")
|
51
|
-
|
52
|
-
index_node_action = getattr(getattr(get_self(), service), action)
|
53
|
-
action_request = request_type()
|
54
|
-
action_request.ParseFromString(request.payload)
|
55
|
-
response = await index_node_action(action_request)
|
56
|
-
return standalone_pb2.NodeActionResponse(payload=response.SerializeToString())
|
57
|
-
|
58
|
-
async def NodeInfo( # type: ignore
|
59
|
-
self, request: standalone_pb2.NodeInfoRequest, context
|
60
|
-
) -> standalone_pb2.NodeInfoResponse:
|
61
|
-
index_node = get_self()
|
62
|
-
index_node.shard_count = len(os.listdir(os.path.join(cluster_settings.data_path, "shards")))
|
63
|
-
total_disk, _, available_disk = shutil.disk_usage(cluster_settings.data_path)
|
64
|
-
return standalone_pb2.NodeInfoResponse(
|
65
|
-
id=index_node.id,
|
66
|
-
address=index_node.address,
|
67
|
-
shard_count=index_node.shard_count,
|
68
|
-
available_disk=available_disk,
|
69
|
-
total_disk=total_disk,
|
70
|
-
)
|
71
|
-
|
72
|
-
|
73
|
-
async def start_grpc():
|
74
|
-
aio.init_grpc_aio()
|
75
|
-
|
76
|
-
server = get_traced_grpc_server("standalone")
|
77
|
-
|
78
|
-
servicer = StandaloneClusterServiceServicer()
|
79
|
-
server.add_insecure_port(f"0.0.0.0:{settings.standalone_node_port}")
|
80
|
-
standalone_pb2_grpc.add_StandaloneClusterServiceServicer_to_server(servicer, server)
|
81
|
-
|
82
|
-
await server.start()
|
83
|
-
|
84
|
-
return server
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|