e6data-python-connector 2.3.9rc5__tar.gz → 2.3.9rc6__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.
- {e6data_python_connector-2.3.9rc5/e6data_python_connector.egg-info → e6data_python_connector-2.3.9rc6}/PKG-INFO +2 -2
- {e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/README.md +1 -1
- {e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/e6data_python_connector/cluster_manager.py +2 -16
- {e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/e6data_python_connector/e6data_grpc.py +46 -36
- {e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/e6data_python_connector/strategy.py +33 -17
- {e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6/e6data_python_connector.egg-info}/PKG-INFO +2 -2
- {e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/setup.py +1 -1
- {e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/LICENSE +0 -0
- {e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/MANIFEST.in +0 -0
- {e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/e6data_python_connector/__init__.py +0 -0
- {e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/e6data_python_connector/cluster_server/__init__.py +0 -0
- {e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/e6data_python_connector/cluster_server/cluster_pb2.py +0 -0
- {e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/e6data_python_connector/cluster_server/cluster_pb2_grpc.py +0 -0
- {e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/e6data_python_connector/common.py +0 -0
- {e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/e6data_python_connector/constants.py +0 -0
- {e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/e6data_python_connector/datainputstream.py +0 -0
- {e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/e6data_python_connector/date_time_utils.py +0 -0
- {e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/e6data_python_connector/dialect.py +0 -0
- {e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/e6data_python_connector/e6x_vector/__init__.py +0 -0
- {e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/e6data_python_connector/e6x_vector/constants.py +0 -0
- {e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/e6data_python_connector/e6x_vector/ttypes.py +0 -0
- {e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/e6data_python_connector/exceptions.py +0 -0
- {e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/e6data_python_connector/server/QueryEngineService.py +0 -0
- {e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/e6data_python_connector/server/__init__.py +0 -0
- {e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/e6data_python_connector/server/constants.py +0 -0
- {e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/e6data_python_connector/server/e6x_engine_pb2.py +0 -0
- {e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/e6data_python_connector/server/e6x_engine_pb2.pyi +0 -0
- {e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/e6data_python_connector/server/e6x_engine_pb2_grpc.py +0 -0
- {e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/e6data_python_connector/server/ttypes.py +0 -0
- {e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/e6data_python_connector/typeId.py +0 -0
- {e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/e6data_python_connector.egg-info/SOURCES.txt +0 -0
- {e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/e6data_python_connector.egg-info/dependency_links.txt +0 -0
- {e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/e6data_python_connector.egg-info/entry_points.txt +0 -0
- {e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/e6data_python_connector.egg-info/requires.txt +0 -0
- {e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/e6data_python_connector.egg-info/top_level.txt +0 -0
- {e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/pyproject.toml +0 -0
- {e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/setup.cfg +0 -0
- {e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/test/__init__.py +0 -0
- {e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/test/analyze_38_nines.py +0 -0
- {e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/test/analyze_all_cases.py +0 -0
- {e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/test/analyze_binary.py +0 -0
- {e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/test/analyze_correct_value.py +0 -0
- {e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/test/analyze_fields.py +0 -0
- {e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/test/check_decimal_errors.py +0 -0
- {e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/test/cleanup_test_files.py +0 -0
- {e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/test/debug_38_nines.py +0 -0
- {e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/test/debug_binary.py +0 -0
- {e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/test/final_test.py +0 -0
- {e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/test/move_tests.py +0 -0
- {e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/test/quick_test.py +0 -0
- {e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/test/test_38_nines.py +0 -0
- {e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/test/test_all_decimal128_cases.py +0 -0
- {e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/test/test_cluster_manager_efficiency.py +0 -0
- {e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/test/test_cluster_manager_none_strategy.py +0 -0
- {e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/test/test_cluster_manager_strategy.py +0 -0
- {e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/test/test_comprehensive.py +0 -0
- {e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/test/test_current_implementation.py +0 -0
- {e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/test/test_decimal128_binary_parsing.py +0 -0
- {e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/test/test_decimal128_parsing.py +0 -0
- {e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/test/test_fix.py +0 -0
- {e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/test/test_improved_parsing.py +0 -0
- {e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/test/test_known_case.py +0 -0
- {e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/test/test_manual_analysis.py +0 -0
- {e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/test/test_mock_server.py +0 -0
- {e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/test/test_multiprocessing_fix.py +0 -0
- {e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/test/test_new_implementation.py +0 -0
- {e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/test/test_specific_binary.py +0 -0
- {e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/test/test_strategy.py +0 -0
- {e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/test/test_strategy_logic.py +0 -0
- {e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/test/test_strategy_persistence_fix.py +0 -0
- {e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/test/test_strategy_sharing_fix.py +0 -0
- {e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/test/test_user_binary_value.py +0 -0
- {e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/test/tests.py +0 -0
- {e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/test/tests_grpc.py +0 -0
- {e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/test/validate_decimal128.py +0 -0
- {e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/test/validate_implementation.py +0 -0
- {e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/test/verify_decimal_fix.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: e6data-python-connector
|
|
3
|
-
Version: 2.3.
|
|
3
|
+
Version: 2.3.9rc6
|
|
4
4
|
Summary: Client for the e6data distributed SQL Engine.
|
|
5
5
|
Home-page: https://github.com/e6x-labs/e6data-python-connector
|
|
6
6
|
Author: e6data, Inc.
|
|
@@ -38,7 +38,7 @@ Dynamic: summary
|
|
|
38
38
|
|
|
39
39
|
# e6data Python Connector
|
|
40
40
|
|
|
41
|
-

|
|
42
42
|
|
|
43
43
|
## Introduction
|
|
44
44
|
|
|
@@ -213,30 +213,25 @@ class ClusterManager:
|
|
|
213
213
|
user=self._user,
|
|
214
214
|
password=self._password
|
|
215
215
|
)
|
|
216
|
-
print('STATUS', payload)
|
|
217
216
|
elif request_type == "resume":
|
|
218
217
|
payload = cluster_pb2.ResumeRequest(
|
|
219
218
|
user=self._user,
|
|
220
219
|
password=self._password
|
|
221
220
|
)
|
|
222
|
-
print('RESUME', payload)
|
|
223
221
|
|
|
224
222
|
# If we have an active strategy, use it first
|
|
225
223
|
if current_strategy is not None:
|
|
226
224
|
try:
|
|
227
225
|
if request_type == "status":
|
|
228
|
-
|
|
229
226
|
response = self._get_connection.status(
|
|
230
227
|
payload,
|
|
231
228
|
metadata=_get_grpc_header(cluster=self.cluster_uuid, strategy=current_strategy)
|
|
232
229
|
)
|
|
233
|
-
print('STATUS 2', response, payload)
|
|
234
230
|
elif request_type == "resume":
|
|
235
231
|
response = self._get_connection.resume(
|
|
236
232
|
payload,
|
|
237
233
|
metadata=_get_grpc_header(cluster=self.cluster_uuid, strategy=current_strategy)
|
|
238
234
|
)
|
|
239
|
-
print('RESUME 2', response, payload)
|
|
240
235
|
else:
|
|
241
236
|
raise ValueError(f"Unknown request type: {request_type}")
|
|
242
237
|
|
|
@@ -259,13 +254,11 @@ class ClusterManager:
|
|
|
259
254
|
payload,
|
|
260
255
|
metadata=_get_grpc_header(cluster=self.cluster_uuid, strategy=alternative_strategy)
|
|
261
256
|
)
|
|
262
|
-
print('STATUS 3', response, payload)
|
|
263
257
|
elif request_type == "resume":
|
|
264
258
|
response = self._get_connection.resume(
|
|
265
259
|
payload,
|
|
266
260
|
metadata=_get_grpc_header(cluster=self.cluster_uuid, strategy=alternative_strategy)
|
|
267
261
|
)
|
|
268
|
-
print('RESUME 3', response, payload)
|
|
269
262
|
|
|
270
263
|
# Update active strategy since the alternative worked
|
|
271
264
|
_set_active_strategy(alternative_strategy)
|
|
@@ -295,13 +288,11 @@ class ClusterManager:
|
|
|
295
288
|
payload,
|
|
296
289
|
metadata=_get_grpc_header(cluster=self.cluster_uuid, strategy=strategy)
|
|
297
290
|
)
|
|
298
|
-
print('STATUS 4', response, payload)
|
|
299
291
|
elif request_type == "resume":
|
|
300
292
|
response = self._get_connection.resume(
|
|
301
293
|
payload,
|
|
302
294
|
metadata=_get_grpc_header(cluster=self.cluster_uuid, strategy=strategy)
|
|
303
295
|
)
|
|
304
|
-
print('RESUME 4', response, payload)
|
|
305
296
|
else:
|
|
306
297
|
raise ValueError(f"Unknown request type: {request_type}")
|
|
307
298
|
|
|
@@ -374,15 +365,13 @@ class ClusterManager:
|
|
|
374
365
|
# Retrieve the current cluster status with strategy header
|
|
375
366
|
try:
|
|
376
367
|
current_status = self._try_cluster_request("status")
|
|
377
|
-
except _InactiveRpcError
|
|
378
|
-
print('ERROR', e, 'Returning false1')
|
|
368
|
+
except _InactiveRpcError:
|
|
379
369
|
return False
|
|
380
370
|
if current_status.status == 'suspended':
|
|
381
371
|
# Send the resume request with strategy header
|
|
382
372
|
try:
|
|
383
373
|
response = self._try_cluster_request("resume")
|
|
384
|
-
except _InactiveRpcError
|
|
385
|
-
print('ERROR', e, 'Returning false2')
|
|
374
|
+
except _InactiveRpcError:
|
|
386
375
|
return False
|
|
387
376
|
elif current_status.status == 'active':
|
|
388
377
|
return True
|
|
@@ -391,18 +380,15 @@ class ClusterManager:
|
|
|
391
380
|
If cluster cannot be resumed due to its current state,
|
|
392
381
|
or already in a process of resuming, terminate the operation.
|
|
393
382
|
"""
|
|
394
|
-
print('ERROR', '!resuming', 'Returning false3')
|
|
395
383
|
return False
|
|
396
384
|
|
|
397
385
|
for status in self._check_cluster_status():
|
|
398
386
|
if status == 'active':
|
|
399
387
|
return True
|
|
400
388
|
elif status == 'failed' or time.time() > self._timeout:
|
|
401
|
-
print('ERROR', 'timed-out', 'Returning false3')
|
|
402
389
|
return False
|
|
403
390
|
# Wait for 5 seconds before the next status check
|
|
404
391
|
time.sleep(5)
|
|
405
|
-
print('ERROR', 'Nothing worked', 'Returning false3')
|
|
406
392
|
return False
|
|
407
393
|
|
|
408
394
|
def suspend(self):
|
|
@@ -7,6 +7,7 @@ from __future__ import absolute_import
|
|
|
7
7
|
from __future__ import unicode_literals
|
|
8
8
|
|
|
9
9
|
import datetime
|
|
10
|
+
import logging
|
|
10
11
|
import re
|
|
11
12
|
import sys
|
|
12
13
|
import time
|
|
@@ -27,6 +28,9 @@ from e6data_python_connector.datainputstream import get_query_columns_info, read
|
|
|
27
28
|
from e6data_python_connector.server import e6x_engine_pb2_grpc, e6x_engine_pb2
|
|
28
29
|
from e6data_python_connector.typeId import *
|
|
29
30
|
|
|
31
|
+
# Set up logging
|
|
32
|
+
logger = logging.getLogger(__name__)
|
|
33
|
+
|
|
30
34
|
apilevel = '2.0'
|
|
31
35
|
threadsafety = 2 # Threads may share the e6xdb and connections.
|
|
32
36
|
paramstyle = 'pyformat' # Python extended format codes, e.g. ...WHERE name=%(name)s
|
|
@@ -134,20 +138,20 @@ def _get_shared_strategy():
|
|
|
134
138
|
global _strategy_manager, _shared_strategy
|
|
135
139
|
|
|
136
140
|
# Try to use multiprocessing.Manager for process-safe storage
|
|
137
|
-
try:
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
except:
|
|
149
|
-
|
|
150
|
-
|
|
141
|
+
# try:
|
|
142
|
+
# if _strategy_manager is None:
|
|
143
|
+
# _strategy_manager = multiprocessing.Manager()
|
|
144
|
+
# _shared_strategy = _strategy_manager.dict()
|
|
145
|
+
# _shared_strategy['active_strategy'] = None
|
|
146
|
+
# _shared_strategy['last_check_time'] = 0
|
|
147
|
+
# _shared_strategy['pending_strategy'] = None
|
|
148
|
+
# _shared_strategy['query_strategy_map'] = _strategy_manager.dict()
|
|
149
|
+
# _shared_strategy['last_transition_time'] = 0
|
|
150
|
+
# _shared_strategy['session_invalidated'] = False
|
|
151
|
+
# return _shared_strategy
|
|
152
|
+
# except:
|
|
153
|
+
# # Fall back to thread-local storage if Manager fails
|
|
154
|
+
return _local_strategy_cache
|
|
151
155
|
|
|
152
156
|
|
|
153
157
|
def _get_active_strategy():
|
|
@@ -177,8 +181,11 @@ def _set_active_strategy(strategy):
|
|
|
177
181
|
current_time = time.time()
|
|
178
182
|
|
|
179
183
|
# Only update transition time if strategy actually changed
|
|
180
|
-
|
|
184
|
+
old_strategy = shared_strategy['active_strategy']
|
|
185
|
+
if old_strategy != normalized_strategy:
|
|
181
186
|
shared_strategy['last_transition_time'] = current_time
|
|
187
|
+
# Debug log for strategy switches
|
|
188
|
+
logger.debug(f"Strategy switched from {old_strategy} to {normalized_strategy}")
|
|
182
189
|
|
|
183
190
|
shared_strategy['active_strategy'] = normalized_strategy
|
|
184
191
|
shared_strategy['last_check_time'] = current_time
|
|
@@ -207,7 +214,12 @@ def _set_pending_strategy(strategy):
|
|
|
207
214
|
current_active = shared_strategy['active_strategy']
|
|
208
215
|
|
|
209
216
|
if normalized_strategy != current_active:
|
|
217
|
+
old_pending = shared_strategy.get('pending_strategy')
|
|
210
218
|
shared_strategy['pending_strategy'] = normalized_strategy
|
|
219
|
+
|
|
220
|
+
# Debug log for pending strategy changes
|
|
221
|
+
if old_pending != normalized_strategy:
|
|
222
|
+
logger.debug(f"Pending strategy changed from {old_pending} to {normalized_strategy}")
|
|
211
223
|
|
|
212
224
|
|
|
213
225
|
def _apply_pending_strategy():
|
|
@@ -219,12 +231,15 @@ def _apply_pending_strategy():
|
|
|
219
231
|
new_strategy = shared_strategy['pending_strategy']
|
|
220
232
|
current_time = time.time()
|
|
221
233
|
|
|
234
|
+
logger.debug(f"Strategy transition initiated: {old_strategy} -> {new_strategy}")
|
|
235
|
+
|
|
222
236
|
shared_strategy['active_strategy'] = new_strategy
|
|
223
237
|
shared_strategy['pending_strategy'] = None
|
|
224
238
|
shared_strategy['last_check_time'] = current_time
|
|
225
239
|
shared_strategy['last_transition_time'] = current_time
|
|
226
240
|
shared_strategy['session_invalidated'] = True # Invalidate all sessions
|
|
227
241
|
|
|
242
|
+
logger.debug(f"Strategy successfully applied and sessions invalidated")
|
|
228
243
|
return new_strategy
|
|
229
244
|
return None
|
|
230
245
|
|
|
@@ -380,7 +395,6 @@ class Connection(object):
|
|
|
380
395
|
"""
|
|
381
396
|
self.grpc_auto_resume_timeout_seconds = self._grpc_options.pop('grpc_auto_resume_timeout_seconds')
|
|
382
397
|
self._create_client()
|
|
383
|
-
self._hash = str(datetime.datetime.now().timestamp()) + 'hash' + str(id(self))
|
|
384
398
|
|
|
385
399
|
@property
|
|
386
400
|
def _get_grpc_options(self):
|
|
@@ -521,7 +535,6 @@ class Connection(object):
|
|
|
521
535
|
_set_pending_strategy(new_strategy)
|
|
522
536
|
# Don't apply immediately - let new queries use fresh connections
|
|
523
537
|
except _InactiveRpcError as e:
|
|
524
|
-
print(self._hash, self.cluster_name, 'Error during authentication with active strategy:', active_strategy, file=sys.stderr)
|
|
525
538
|
if e.code() == grpc.StatusCode.UNKNOWN and 'status: 456' in e.details():
|
|
526
539
|
# Strategy changed, clear cache and retry
|
|
527
540
|
_clear_strategy_cache()
|
|
@@ -563,7 +576,6 @@ class Connection(object):
|
|
|
563
576
|
# Don't apply immediately - let new queries use fresh connections
|
|
564
577
|
break
|
|
565
578
|
except _InactiveRpcError as e:
|
|
566
|
-
print(self._hash, self.cluster_name, 'Error during authentication with strategy:', strategy, file=sys.stderr)
|
|
567
579
|
if e.code() == grpc.StatusCode.UNKNOWN and 'status: 456' in e.details():
|
|
568
580
|
# Wrong strategy, try the next one
|
|
569
581
|
last_error = e
|
|
@@ -590,24 +602,23 @@ class Connection(object):
|
|
|
590
602
|
cluster_uuid=self.cluster_name,
|
|
591
603
|
timeout=self.grpc_auto_resume_timeout_seconds
|
|
592
604
|
).resume()
|
|
593
|
-
print(self._hash, self.cluster_name, 'Cluster resume status:', status, file=sys.stderr)
|
|
594
605
|
if status:
|
|
595
|
-
|
|
596
|
-
authenticate_request = e6x_engine_pb2.AuthenticateRequest(
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
)
|
|
600
|
-
authenticate_response = self._client.authenticate(
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
)
|
|
604
|
-
self._session_id = authenticate_response.sessionId
|
|
605
|
-
# Check for new strategy in authenticate response
|
|
606
|
-
if hasattr(authenticate_response, 'new_strategy') and authenticate_response.new_strategy:
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
606
|
+
return self.get_session_id
|
|
607
|
+
# authenticate_request = e6x_engine_pb2.AuthenticateRequest(
|
|
608
|
+
# user=self.__username,
|
|
609
|
+
# password=self.__password
|
|
610
|
+
# )
|
|
611
|
+
# authenticate_response = self._client.authenticate(
|
|
612
|
+
# authenticate_request,
|
|
613
|
+
# metadata=_get_grpc_header(cluster=self.cluster_uuid, strategy=_get_active_strategy())
|
|
614
|
+
# )
|
|
615
|
+
# self._session_id = authenticate_response.sessionId
|
|
616
|
+
# # Check for new strategy in authenticate response
|
|
617
|
+
# if hasattr(authenticate_response, 'new_strategy') and authenticate_response.new_strategy:
|
|
618
|
+
# new_strategy = authenticate_response.new_strategy.lower()
|
|
619
|
+
# if new_strategy != _get_active_strategy():
|
|
620
|
+
# _set_pending_strategy(new_strategy)
|
|
621
|
+
# # Don't apply immediately - let new queries use fresh connections
|
|
611
622
|
else:
|
|
612
623
|
raise e
|
|
613
624
|
else:
|
|
@@ -615,7 +626,6 @@ class Connection(object):
|
|
|
615
626
|
else:
|
|
616
627
|
raise e
|
|
617
628
|
except Exception as e:
|
|
618
|
-
print(self._hash, self.cluster_name, 'Error during authentication:', e, file=sys.stderr)
|
|
619
629
|
self._channel.close()
|
|
620
630
|
raise e
|
|
621
631
|
return self._session_id
|
|
@@ -41,23 +41,23 @@ def _initialize_shared_state():
|
|
|
41
41
|
if _shared_strategy is not None:
|
|
42
42
|
return _shared_strategy
|
|
43
43
|
|
|
44
|
-
try:
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
except Exception as e:
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
44
|
+
# try:
|
|
45
|
+
# # Try to create multiprocessing Manager
|
|
46
|
+
# _manager = multiprocessing.Manager()
|
|
47
|
+
# _shared_strategy = _manager.dict({
|
|
48
|
+
# 'active_strategy': None,
|
|
49
|
+
# 'last_check_time': 0,
|
|
50
|
+
# 'pending_strategy': None,
|
|
51
|
+
# 'query_strategy_map': _manager.dict(),
|
|
52
|
+
# 'last_transition_time': 0,
|
|
53
|
+
# 'session_invalidated': False
|
|
54
|
+
# })
|
|
55
|
+
# _logger.debug("Successfully initialized multiprocessing Manager for strategy sharing")
|
|
56
|
+
# return _shared_strategy
|
|
57
|
+
# except Exception as e:
|
|
58
|
+
# # Fall back to thread-local storage if Manager fails
|
|
59
|
+
# _logger.warning(f"Failed to initialize multiprocessing Manager: {e}. Using thread-local storage.")
|
|
60
|
+
return _local_strategy_cache
|
|
61
61
|
|
|
62
62
|
|
|
63
63
|
def _get_shared_strategy():
|
|
@@ -85,8 +85,14 @@ def _set_active_strategy(strategy):
|
|
|
85
85
|
_logger.warning(f"Invalid strategy value: {strategy}. Must be 'blue' or 'green'.")
|
|
86
86
|
return
|
|
87
87
|
|
|
88
|
+
old_strategy = shared_strategy.get('active_strategy')
|
|
88
89
|
shared_strategy['active_strategy'] = normalized_strategy
|
|
89
90
|
shared_strategy['last_check_time'] = time.time()
|
|
91
|
+
|
|
92
|
+
# Debug log for strategy switches
|
|
93
|
+
if old_strategy != normalized_strategy:
|
|
94
|
+
_logger.debug(f"Strategy switched from {old_strategy} to {normalized_strategy}")
|
|
95
|
+
|
|
90
96
|
_logger.info(f"Active deployment strategy set to: {normalized_strategy}")
|
|
91
97
|
|
|
92
98
|
|
|
@@ -105,7 +111,13 @@ def _set_pending_strategy(strategy):
|
|
|
105
111
|
|
|
106
112
|
current_active = shared_strategy.get('active_strategy')
|
|
107
113
|
if normalized_strategy != current_active:
|
|
114
|
+
old_pending = shared_strategy.get('pending_strategy')
|
|
108
115
|
shared_strategy['pending_strategy'] = normalized_strategy
|
|
116
|
+
|
|
117
|
+
# Debug log for pending strategy changes
|
|
118
|
+
if old_pending != normalized_strategy:
|
|
119
|
+
_logger.debug(f"Pending strategy changed from {old_pending} to {normalized_strategy}")
|
|
120
|
+
|
|
109
121
|
_logger.info(f"Pending deployment strategy set to: {normalized_strategy}")
|
|
110
122
|
|
|
111
123
|
|
|
@@ -160,11 +172,15 @@ def _apply_pending_strategy():
|
|
|
160
172
|
if len(query_map) == 0:
|
|
161
173
|
# No active queries, safe to transition
|
|
162
174
|
_logger.info(f"Last query completed, applying pending strategy: {pending_strategy}")
|
|
175
|
+
_logger.debug(f"Strategy transition initiated: {active_strategy} -> {pending_strategy}")
|
|
176
|
+
|
|
163
177
|
shared_strategy['active_strategy'] = pending_strategy
|
|
164
178
|
shared_strategy['pending_strategy'] = None
|
|
165
179
|
shared_strategy['last_transition_time'] = time.time()
|
|
166
180
|
shared_strategy['session_invalidated'] = True # Invalidate all sessions
|
|
181
|
+
|
|
167
182
|
_logger.info(f"Strategy transition completed: {active_strategy} -> {pending_strategy}")
|
|
183
|
+
_logger.debug(f"Strategy successfully applied and sessions invalidated")
|
|
168
184
|
|
|
169
185
|
|
|
170
186
|
def _is_strategy_cache_valid():
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: e6data-python-connector
|
|
3
|
-
Version: 2.3.
|
|
3
|
+
Version: 2.3.9rc6
|
|
4
4
|
Summary: Client for the e6data distributed SQL Engine.
|
|
5
5
|
Home-page: https://github.com/e6x-labs/e6data-python-connector
|
|
6
6
|
Author: e6data, Inc.
|
|
@@ -38,7 +38,7 @@ Dynamic: summary
|
|
|
38
38
|
|
|
39
39
|
# e6data Python Connector
|
|
40
40
|
|
|
41
|
-

|
|
42
42
|
|
|
43
43
|
## Introduction
|
|
44
44
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/test/analyze_38_nines.py
RENAMED
|
File without changes
|
{e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/test/analyze_all_cases.py
RENAMED
|
File without changes
|
{e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/test/analyze_binary.py
RENAMED
|
File without changes
|
{e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/test/analyze_correct_value.py
RENAMED
|
File without changes
|
{e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/test/analyze_fields.py
RENAMED
|
File without changes
|
{e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/test/check_decimal_errors.py
RENAMED
|
File without changes
|
{e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/test/cleanup_test_files.py
RENAMED
|
File without changes
|
{e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/test/debug_38_nines.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/test/test_comprehensive.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/test/test_improved_parsing.py
RENAMED
|
File without changes
|
{e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/test/test_known_case.py
RENAMED
|
File without changes
|
{e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/test/test_manual_analysis.py
RENAMED
|
File without changes
|
{e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/test/test_mock_server.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/test/test_specific_binary.py
RENAMED
|
File without changes
|
|
File without changes
|
{e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/test/test_strategy_logic.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/test/test_user_binary_value.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/test/validate_decimal128.py
RENAMED
|
File without changes
|
|
File without changes
|
{e6data_python_connector-2.3.9rc5 → e6data_python_connector-2.3.9rc6}/test/verify_decimal_fix.py
RENAMED
|
File without changes
|