Skip to content

Commit dcdcf49

Browse files
fix(csharp): always send CloseOperation from DatabricksCompositeReader.Dispose
Previously, DatabricksCompositeReader.Dispose only called CloseOperation when _activeReader was null. When a CloudFetchReader was active, it delegated Dispose to the reader, but CloudFetchReader is protocol-agnostic and never sends CloseOperation. This orphaned every CloudFetch server operation for ~1 hour until SQL Gateway fired CommandInactivityTimeout, producing thriftOperationCloseReason=CommandInactivityTimeout in usage logs. Move CloseOperation ownership entirely to DatabricksCompositeReader.Dispose, which holds both _statement (Thrift client) and _response (operation handle). HiveServer2Reader.CloseOperationAsync is already a no-op when DirectResults already closed the operation server-side, so all three result paths are safe: - Inline + DirectResults enabled: CloseOperation is a no-op (already closed) - Inline + DirectResults disabled: CloseOperation sent explicitly - CloudFetch: CloseOperation sent explicitly (was previously missing) Remove CloseOperation from DatabricksReader.Dispose to avoid duplicate calls; DatabricksReader is only ever constructed from DatabricksCompositeReader.
1 parent d4083ce commit dcdcf49

File tree

2 files changed

+7
-12
lines changed

2 files changed

+7
-12
lines changed

csharp/src/Reader/DatabricksCompositeReader.cs

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -237,18 +237,17 @@ protected override void Dispose(bool disposing)
237237
{
238238
activity?.AddEvent("composite_reader.disposing");
239239
StopOperationStatusPoller();
240-
if (_activeReader == null)
241-
{
242-
activity?.AddEvent("composite_reader.close_operation_no_reader");
243-
_ = HiveServer2Reader.CloseOperationAsync(_statement, _response)
244-
.ConfigureAwait(false).GetAwaiter().GetResult();
245-
}
246-
else
240+
// Always close the operation here at the composite level.
241+
// CloudFetchReader is protocol-agnostic and does not send CloseOperation,
242+
// so we must not rely on the contained reader to do it.
243+
activity?.AddEvent("composite_reader.close_operation");
244+
_ = HiveServer2Reader.CloseOperationAsync(_statement, _response)
245+
.ConfigureAwait(false).GetAwaiter().GetResult();
246+
if (_activeReader != null)
247247
{
248248
activity?.AddEvent("composite_reader.disposing_active_reader", [
249249
new("reader_type", _activeReader.GetType().Name)
250250
]);
251-
// Note: Have the contained reader close the operation to avoid duplicate calls.
252251
_activeReader.Dispose();
253252
_activeReader = null;
254253
}

csharp/src/Reader/DatabricksReader.cs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -241,10 +241,6 @@ _ when ex.GetType().Name.Contains("LZ4") => $"Batch {this.index}: LZ4 decompress
241241

242242
protected override void Dispose(bool disposing)
243243
{
244-
if (disposing)
245-
{
246-
_ = CloseOperationAsync().Result;
247-
}
248244
base.Dispose(disposing);
249245
}
250246

0 commit comments

Comments
 (0)