e6data-python-connector 2.3.9rc7__tar.gz → 2.3.9rc9__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.9rc7/e6data_python_connector.egg-info → e6data_python_connector-2.3.9rc9}/PKG-INFO +2 -2
- {e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/README.md +1 -1
- {e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/e6data_python_connector/dialect.py +3 -1
- {e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/e6data_python_connector/e6data_grpc.py +55 -17
- {e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/e6data_python_connector/strategy.py +1 -18
- {e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9/e6data_python_connector.egg-info}/PKG-INFO +2 -2
- {e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/setup.py +1 -1
- {e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/LICENSE +0 -0
- {e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/MANIFEST.in +0 -0
- {e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/e6data_python_connector/__init__.py +0 -0
- {e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/e6data_python_connector/cluster_manager.py +0 -0
- {e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/e6data_python_connector/cluster_server/__init__.py +0 -0
- {e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/e6data_python_connector/cluster_server/cluster_pb2.py +0 -0
- {e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/e6data_python_connector/cluster_server/cluster_pb2_grpc.py +0 -0
- {e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/e6data_python_connector/common.py +0 -0
- {e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/e6data_python_connector/constants.py +0 -0
- {e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/e6data_python_connector/datainputstream.py +0 -0
- {e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/e6data_python_connector/date_time_utils.py +0 -0
- {e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/e6data_python_connector/e6x_vector/__init__.py +0 -0
- {e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/e6data_python_connector/e6x_vector/constants.py +0 -0
- {e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/e6data_python_connector/e6x_vector/ttypes.py +0 -0
- {e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/e6data_python_connector/exceptions.py +0 -0
- {e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/e6data_python_connector/server/QueryEngineService.py +0 -0
- {e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/e6data_python_connector/server/__init__.py +0 -0
- {e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/e6data_python_connector/server/constants.py +0 -0
- {e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/e6data_python_connector/server/e6x_engine_pb2.py +0 -0
- {e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/e6data_python_connector/server/e6x_engine_pb2.pyi +0 -0
- {e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/e6data_python_connector/server/e6x_engine_pb2_grpc.py +0 -0
- {e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/e6data_python_connector/server/ttypes.py +0 -0
- {e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/e6data_python_connector/typeId.py +0 -0
- {e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/e6data_python_connector.egg-info/SOURCES.txt +0 -0
- {e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/e6data_python_connector.egg-info/dependency_links.txt +0 -0
- {e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/e6data_python_connector.egg-info/entry_points.txt +0 -0
- {e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/e6data_python_connector.egg-info/requires.txt +0 -0
- {e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/e6data_python_connector.egg-info/top_level.txt +0 -0
- {e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/pyproject.toml +0 -0
- {e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/setup.cfg +0 -0
- {e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/test/__init__.py +0 -0
- {e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/test/analyze_38_nines.py +0 -0
- {e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/test/analyze_all_cases.py +0 -0
- {e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/test/analyze_binary.py +0 -0
- {e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/test/analyze_correct_value.py +0 -0
- {e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/test/analyze_fields.py +0 -0
- {e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/test/check_decimal_errors.py +0 -0
- {e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/test/cleanup_test_files.py +0 -0
- {e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/test/debug_38_nines.py +0 -0
- {e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/test/debug_binary.py +0 -0
- {e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/test/final_test.py +0 -0
- {e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/test/move_tests.py +0 -0
- {e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/test/quick_test.py +0 -0
- {e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/test/test_38_nines.py +0 -0
- {e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/test/test_all_decimal128_cases.py +0 -0
- {e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/test/test_cluster_manager_efficiency.py +0 -0
- {e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/test/test_cluster_manager_none_strategy.py +0 -0
- {e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/test/test_cluster_manager_strategy.py +0 -0
- {e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/test/test_comprehensive.py +0 -0
- {e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/test/test_current_implementation.py +0 -0
- {e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/test/test_decimal128_binary_parsing.py +0 -0
- {e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/test/test_decimal128_parsing.py +0 -0
- {e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/test/test_fix.py +0 -0
- {e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/test/test_improved_parsing.py +0 -0
- {e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/test/test_known_case.py +0 -0
- {e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/test/test_manual_analysis.py +0 -0
- {e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/test/test_mock_server.py +0 -0
- {e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/test/test_multiprocessing_fix.py +0 -0
- {e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/test/test_new_implementation.py +0 -0
- {e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/test/test_specific_binary.py +0 -0
- {e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/test/test_strategy.py +0 -0
- {e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/test/test_strategy_logic.py +0 -0
- {e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/test/test_strategy_persistence_fix.py +0 -0
- {e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/test/test_strategy_sharing_fix.py +0 -0
- {e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/test/test_user_binary_value.py +0 -0
- {e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/test/tests.py +0 -0
- {e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/test/tests_grpc.py +0 -0
- {e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/test/validate_decimal128.py +0 -0
- {e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/test/validate_implementation.py +0 -0
- {e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/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.9rc9
|
|
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
|
|
|
@@ -229,6 +229,7 @@ class E6dataDialect(default.DefaultDialect):
|
|
|
229
229
|
self.cluster_name = url.query.get("cluster-name")
|
|
230
230
|
self.secure = url.query.get("secure") == "true"
|
|
231
231
|
self.auto_resume = url.query.get("auto-resume", "true") == "true" # default to True
|
|
232
|
+
self.debug = url.query.get("debug", "false") == "true" # default to True
|
|
232
233
|
if not self.catalog_name:
|
|
233
234
|
raise Exception('Please specify catalog in query parameter.')
|
|
234
235
|
|
|
@@ -250,7 +251,8 @@ class E6dataDialect(default.DefaultDialect):
|
|
|
250
251
|
"cluster_name": self.cluster_name,
|
|
251
252
|
'secure': self.secure,
|
|
252
253
|
'auto_resume': self.auto_resume,
|
|
253
|
-
'grpc_options': grpc_options
|
|
254
|
+
'grpc_options': grpc_options,
|
|
255
|
+
'debug': self.debug
|
|
254
256
|
}
|
|
255
257
|
return [], kwargs
|
|
256
258
|
|
|
@@ -128,26 +128,19 @@ _local_strategy_cache = {
|
|
|
128
128
|
# Strategy cache timeout in seconds (5 minutes)
|
|
129
129
|
STRATEGY_CACHE_TIMEOUT = 300
|
|
130
130
|
|
|
131
|
+
# Global set to track debug-enabled connections
|
|
132
|
+
_debug_connections = set()
|
|
133
|
+
|
|
134
|
+
def _strategy_debug_log(message):
|
|
135
|
+
"""Log strategy debug messages if any connection has debug enabled."""
|
|
136
|
+
if _debug_connections:
|
|
137
|
+
print(f"[E6DATA_STRATEGY_DEBUG] {time.strftime('%Y-%m-%d %H:%M:%S')} - {message}")
|
|
138
|
+
|
|
131
139
|
|
|
132
140
|
def _get_shared_strategy():
|
|
133
141
|
"""Get or create the shared strategy storage."""
|
|
134
142
|
global _strategy_manager, _shared_strategy
|
|
135
|
-
|
|
136
|
-
# Try to use multiprocessing.Manager for process-safe storage
|
|
137
|
-
try:
|
|
138
|
-
if _strategy_manager is None:
|
|
139
|
-
_strategy_manager = multiprocessing.Manager()
|
|
140
|
-
_shared_strategy = _strategy_manager.dict()
|
|
141
|
-
_shared_strategy['active_strategy'] = None
|
|
142
|
-
_shared_strategy['last_check_time'] = 0
|
|
143
|
-
_shared_strategy['pending_strategy'] = None
|
|
144
|
-
_shared_strategy['query_strategy_map'] = _strategy_manager.dict()
|
|
145
|
-
_shared_strategy['last_transition_time'] = 0
|
|
146
|
-
_shared_strategy['session_invalidated'] = False
|
|
147
|
-
return _shared_strategy
|
|
148
|
-
except:
|
|
149
|
-
# Fall back to thread-local storage if Manager fails
|
|
150
|
-
return _local_strategy_cache
|
|
143
|
+
return _local_strategy_cache
|
|
151
144
|
|
|
152
145
|
|
|
153
146
|
def _get_active_strategy():
|
|
@@ -175,10 +168,14 @@ def _set_active_strategy(strategy):
|
|
|
175
168
|
with _strategy_lock:
|
|
176
169
|
shared_strategy = _get_shared_strategy()
|
|
177
170
|
current_time = time.time()
|
|
171
|
+
old_strategy = shared_strategy.get('active_strategy')
|
|
178
172
|
|
|
179
173
|
# Only update transition time if strategy actually changed
|
|
180
|
-
if
|
|
174
|
+
if old_strategy != normalized_strategy:
|
|
181
175
|
shared_strategy['last_transition_time'] = current_time
|
|
176
|
+
_strategy_debug_log(f"Setting active strategy: {old_strategy} -> {normalized_strategy}")
|
|
177
|
+
else:
|
|
178
|
+
_strategy_debug_log(f"Active strategy unchanged: {normalized_strategy}")
|
|
182
179
|
|
|
183
180
|
shared_strategy['active_strategy'] = normalized_strategy
|
|
184
181
|
shared_strategy['last_check_time'] = current_time
|
|
@@ -188,6 +185,9 @@ def _clear_strategy_cache():
|
|
|
188
185
|
"""Clear the cached strategy to force re-detection."""
|
|
189
186
|
with _strategy_lock:
|
|
190
187
|
shared_strategy = _get_shared_strategy()
|
|
188
|
+
old_strategy = shared_strategy.get('active_strategy')
|
|
189
|
+
if old_strategy:
|
|
190
|
+
_strategy_debug_log(f"Clearing strategy cache (was: {old_strategy})")
|
|
191
191
|
shared_strategy['active_strategy'] = None
|
|
192
192
|
shared_strategy['last_check_time'] = 0
|
|
193
193
|
shared_strategy['pending_strategy'] = None
|
|
@@ -208,6 +208,8 @@ def _set_pending_strategy(strategy):
|
|
|
208
208
|
|
|
209
209
|
if normalized_strategy != current_active:
|
|
210
210
|
shared_strategy['pending_strategy'] = normalized_strategy
|
|
211
|
+
query_count = len(shared_strategy.get('query_strategy_map', {}))
|
|
212
|
+
_strategy_debug_log(f"Setting pending strategy: {normalized_strategy} (current: {current_active}, active queries: {query_count})")
|
|
211
213
|
|
|
212
214
|
|
|
213
215
|
def _apply_pending_strategy():
|
|
@@ -215,14 +217,19 @@ def _apply_pending_strategy():
|
|
|
215
217
|
with _strategy_lock:
|
|
216
218
|
shared_strategy = _get_shared_strategy()
|
|
217
219
|
if shared_strategy['pending_strategy']:
|
|
220
|
+
old_strategy = shared_strategy['active_strategy']
|
|
218
221
|
new_strategy = shared_strategy['pending_strategy']
|
|
219
222
|
current_time = time.time()
|
|
220
223
|
|
|
224
|
+
_strategy_debug_log(f"Applying pending strategy: {old_strategy} -> {new_strategy}")
|
|
225
|
+
|
|
221
226
|
shared_strategy['active_strategy'] = new_strategy
|
|
222
227
|
shared_strategy['pending_strategy'] = None
|
|
223
228
|
shared_strategy['last_check_time'] = current_time
|
|
224
229
|
shared_strategy['last_transition_time'] = current_time
|
|
225
230
|
shared_strategy['session_invalidated'] = True # Invalidate all sessions
|
|
231
|
+
|
|
232
|
+
_strategy_debug_log(f"Strategy transition complete. All sessions invalidated.")
|
|
226
233
|
|
|
227
234
|
return new_strategy
|
|
228
235
|
return None
|
|
@@ -249,6 +256,7 @@ def _register_query_strategy(query_id, strategy):
|
|
|
249
256
|
query_map = shared_strategy.get('query_strategy_map', {})
|
|
250
257
|
query_map[query_id] = normalized_strategy
|
|
251
258
|
shared_strategy['query_strategy_map'] = query_map
|
|
259
|
+
_strategy_debug_log(f"Query {query_id} registered with strategy: {normalized_strategy}")
|
|
252
260
|
|
|
253
261
|
|
|
254
262
|
def _get_query_strategy(query_id):
|
|
@@ -270,8 +278,11 @@ def _cleanup_query_strategy(query_id):
|
|
|
270
278
|
shared_strategy = _get_shared_strategy()
|
|
271
279
|
query_map = shared_strategy.get('query_strategy_map', {})
|
|
272
280
|
if query_id in query_map:
|
|
281
|
+
strategy = query_map[query_id]
|
|
273
282
|
del query_map[query_id]
|
|
274
283
|
shared_strategy['query_strategy_map'] = query_map
|
|
284
|
+
remaining_queries = len(query_map)
|
|
285
|
+
_strategy_debug_log(f"Query {query_id} completed (was using {strategy}). Remaining active queries: {remaining_queries}")
|
|
275
286
|
|
|
276
287
|
|
|
277
288
|
def _get_strategy_debug_info():
|
|
@@ -318,6 +329,7 @@ class Connection(object):
|
|
|
318
329
|
auto_resume: bool = True,
|
|
319
330
|
scheme: str = 'e6data',
|
|
320
331
|
grpc_options: dict = None,
|
|
332
|
+
debug: bool = False,
|
|
321
333
|
):
|
|
322
334
|
"""
|
|
323
335
|
Parameters
|
|
@@ -349,6 +361,8 @@ class Connection(object):
|
|
|
349
361
|
- max_send_message_length: Similar to max_receive_message_length, this parameter sets the maximum allowed size (in bytes) for outgoing messages from the gRPC client
|
|
350
362
|
- grpc_prepare_timeout: Timeout for prepare statement API call (default to 10 minutes).
|
|
351
363
|
- keepalive_time_ms: This parameter defines the time, in milliseconds, Default to 30 seconds
|
|
364
|
+
debug: bool, Optional
|
|
365
|
+
Flag to enable debug logging for blue-green deployment strategy changes
|
|
352
366
|
"""
|
|
353
367
|
if not username or not password:
|
|
354
368
|
raise ValueError("username or password cannot be empty.")
|
|
@@ -378,6 +392,13 @@ class Connection(object):
|
|
|
378
392
|
The default maximum time on client side to wait for the cluster to resume is 5 minutes.
|
|
379
393
|
"""
|
|
380
394
|
self.grpc_auto_resume_timeout_seconds = self._grpc_options.pop('grpc_auto_resume_timeout_seconds')
|
|
395
|
+
|
|
396
|
+
# Store debug flag and register with debug connections
|
|
397
|
+
self._debug = debug
|
|
398
|
+
if self._debug:
|
|
399
|
+
_debug_connections.add(id(self))
|
|
400
|
+
_strategy_debug_log(f"Debug mode enabled for connection {id(self)}")
|
|
401
|
+
|
|
381
402
|
self._create_client()
|
|
382
403
|
|
|
383
404
|
@property
|
|
@@ -504,6 +525,7 @@ class Connection(object):
|
|
|
504
525
|
|
|
505
526
|
if active_strategy and not pending_strategy:
|
|
506
527
|
# Use cached strategy only if there's no pending strategy
|
|
528
|
+
_strategy_debug_log(f"Authenticating with cached strategy: {active_strategy}")
|
|
507
529
|
try:
|
|
508
530
|
authenticate_response = self._client.authenticate(
|
|
509
531
|
authenticate_request,
|
|
@@ -519,10 +541,13 @@ class Connection(object):
|
|
|
519
541
|
_set_pending_strategy(new_strategy)
|
|
520
542
|
_apply_pending_strategy()
|
|
521
543
|
self._session_id = None
|
|
544
|
+
self.close()
|
|
545
|
+
self._create_client()
|
|
522
546
|
return self.get_session_id
|
|
523
547
|
except _InactiveRpcError as e:
|
|
524
548
|
if e.code() == grpc.StatusCode.UNKNOWN and 'status: 456' in e.details():
|
|
525
549
|
# Strategy changed, clear cache and retry
|
|
550
|
+
_strategy_debug_log(f"Got 456 error with strategy {active_strategy}, clearing cache and retrying")
|
|
526
551
|
_clear_strategy_cache()
|
|
527
552
|
active_strategy = None
|
|
528
553
|
else:
|
|
@@ -541,8 +566,10 @@ class Connection(object):
|
|
|
541
566
|
else:
|
|
542
567
|
# Always try blue first, then green if it fails with 456
|
|
543
568
|
strategies = ['blue', 'green']
|
|
569
|
+
_strategy_debug_log(f"No cached strategy, will try strategies in order: {strategies}")
|
|
544
570
|
last_error = None
|
|
545
571
|
for strategy in strategies:
|
|
572
|
+
_strategy_debug_log(f"Attempting authentication with strategy: {strategy}")
|
|
546
573
|
try:
|
|
547
574
|
authenticate_response = self._client.authenticate(
|
|
548
575
|
authenticate_request,
|
|
@@ -551,6 +578,7 @@ class Connection(object):
|
|
|
551
578
|
self._session_id = authenticate_response.sessionId
|
|
552
579
|
if self._session_id:
|
|
553
580
|
# Success! Cache this strategy
|
|
581
|
+
_strategy_debug_log(f"Authentication successful with strategy: {strategy}")
|
|
554
582
|
_set_active_strategy(strategy)
|
|
555
583
|
|
|
556
584
|
# Check for new strategy in authenticate response
|
|
@@ -559,12 +587,15 @@ class Connection(object):
|
|
|
559
587
|
if new_strategy != strategy:
|
|
560
588
|
_set_pending_strategy(new_strategy)
|
|
561
589
|
_apply_pending_strategy()
|
|
590
|
+
self.close()
|
|
591
|
+
self._create_client()
|
|
562
592
|
self._session_id = None
|
|
563
593
|
return self.get_session_id
|
|
564
594
|
break
|
|
565
595
|
except _InactiveRpcError as e:
|
|
566
596
|
if e.code() == grpc.StatusCode.UNKNOWN and 'status: 456' in e.details():
|
|
567
597
|
# Wrong strategy, try the next one
|
|
598
|
+
_strategy_debug_log(f"Strategy {strategy} failed with 456 error, trying next")
|
|
568
599
|
last_error = e
|
|
569
600
|
continue
|
|
570
601
|
else:
|
|
@@ -636,6 +667,11 @@ class Connection(object):
|
|
|
636
667
|
self._channel.close()
|
|
637
668
|
self._channel = None
|
|
638
669
|
self._session_id = None
|
|
670
|
+
|
|
671
|
+
# Remove from debug connections if debug was enabled
|
|
672
|
+
if self._debug:
|
|
673
|
+
_debug_connections.discard(id(self))
|
|
674
|
+
_strategy_debug_log(f"Debug mode disabled for connection {id(self)}")
|
|
639
675
|
|
|
640
676
|
def check_connection(self):
|
|
641
677
|
"""
|
|
@@ -1082,6 +1118,7 @@ class Cursor(DBAPICursor):
|
|
|
1082
1118
|
query_map = shared_strategy.get('query_strategy_map', {})
|
|
1083
1119
|
|
|
1084
1120
|
if pending_strategy and len(query_map) == 0:
|
|
1121
|
+
_strategy_debug_log(f"Last query cleared, triggering pending strategy transition")
|
|
1085
1122
|
_apply_pending_strategy()
|
|
1086
1123
|
|
|
1087
1124
|
return clear_response
|
|
@@ -1105,6 +1142,7 @@ class Cursor(DBAPICursor):
|
|
|
1105
1142
|
query_map = shared_strategy.get('query_strategy_map', {})
|
|
1106
1143
|
|
|
1107
1144
|
if pending_strategy and len(query_map) == 0:
|
|
1145
|
+
_strategy_debug_log(f"Last query cleared, triggering pending strategy transition")
|
|
1108
1146
|
_apply_pending_strategy()
|
|
1109
1147
|
|
|
1110
1148
|
def status(self, query_id):
|
|
@@ -40,24 +40,7 @@ def _initialize_shared_state():
|
|
|
40
40
|
with _initialization_lock:
|
|
41
41
|
if _shared_strategy is not None:
|
|
42
42
|
return _shared_strategy
|
|
43
|
-
|
|
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
|
|
43
|
+
return _local_strategy_cache
|
|
61
44
|
|
|
62
45
|
|
|
63
46
|
def _get_shared_strategy():
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: e6data-python-connector
|
|
3
|
-
Version: 2.3.
|
|
3
|
+
Version: 2.3.9rc9
|
|
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.9rc7 → e6data_python_connector-2.3.9rc9}/test/analyze_38_nines.py
RENAMED
|
File without changes
|
{e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/test/analyze_all_cases.py
RENAMED
|
File without changes
|
{e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/test/analyze_binary.py
RENAMED
|
File without changes
|
{e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/test/analyze_correct_value.py
RENAMED
|
File without changes
|
{e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/test/analyze_fields.py
RENAMED
|
File without changes
|
{e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/test/check_decimal_errors.py
RENAMED
|
File without changes
|
{e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/test/cleanup_test_files.py
RENAMED
|
File without changes
|
{e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/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.9rc7 → e6data_python_connector-2.3.9rc9}/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.9rc7 → e6data_python_connector-2.3.9rc9}/test/test_improved_parsing.py
RENAMED
|
File without changes
|
{e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/test/test_known_case.py
RENAMED
|
File without changes
|
{e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/test/test_manual_analysis.py
RENAMED
|
File without changes
|
{e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/test/test_mock_server.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/test/test_specific_binary.py
RENAMED
|
File without changes
|
|
File without changes
|
{e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/test/test_strategy_logic.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/test/test_user_binary_value.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/test/validate_decimal128.py
RENAMED
|
File without changes
|
|
File without changes
|
{e6data_python_connector-2.3.9rc7 → e6data_python_connector-2.3.9rc9}/test/verify_decimal_fix.py
RENAMED
|
File without changes
|