|
19 | 19 | #if SUPPORT_LOAD_BALANCING
|
20 | 20 | using System;
|
21 | 21 | using System.Collections.Generic;
|
| 22 | +using System.Diagnostics; |
22 | 23 | using System.Linq;
|
23 | 24 | using System.Net;
|
24 | 25 | using System.Threading;
|
@@ -56,12 +57,13 @@ public sealed class Subchannel : IDisposable
|
56 | 57 | /// </summary>
|
57 | 58 | internal ConnectivityState State => _state;
|
58 | 59 |
|
59 |
| - private readonly ConnectionManager _manager; |
| 60 | + internal readonly ConnectionManager _manager; |
60 | 61 | private readonly ILogger _logger;
|
61 | 62 |
|
62 | 63 | private ConnectContext? _connectContext;
|
63 | 64 | private ConnectivityState _state;
|
64 | 65 | private TaskCompletionSource<object?>? _delayInterruptTcs;
|
| 66 | + private int _currentRegistrationId; |
65 | 67 |
|
66 | 68 | /// <summary>
|
67 | 69 | /// Gets the current connected address.
|
@@ -101,25 +103,40 @@ public IDisposable OnStateChanged(Action<SubchannelState> callback)
|
101 | 103 | return registration;
|
102 | 104 | }
|
103 | 105 |
|
| 106 | + private string GetNextRegistrationId() |
| 107 | + { |
| 108 | + var registrationId = Interlocked.Increment(ref _currentRegistrationId); |
| 109 | + return Id + "-" + registrationId; |
| 110 | + } |
| 111 | + |
104 | 112 | private sealed class StateChangedRegistration : IDisposable
|
105 | 113 | {
|
106 | 114 | private readonly Subchannel _subchannel;
|
107 | 115 | private readonly Action<SubchannelState> _callback;
|
108 | 116 |
|
| 117 | + public string RegistrationId { get; } |
| 118 | + |
109 | 119 | public StateChangedRegistration(Subchannel subchannel, Action<SubchannelState> callback)
|
110 | 120 | {
|
111 | 121 | _subchannel = subchannel;
|
112 | 122 | _callback = callback;
|
| 123 | + RegistrationId = subchannel.GetNextRegistrationId(); |
| 124 | + |
| 125 | + SubchannelLog.StateChangedRegistrationCreated(_subchannel._logger, _subchannel.Id, RegistrationId); |
113 | 126 | }
|
114 | 127 |
|
115 | 128 | public void Invoke(SubchannelState state)
|
116 | 129 | {
|
| 130 | + SubchannelLog.ExecutingStateChangedRegistration(_subchannel._logger, _subchannel.Id, RegistrationId); |
117 | 131 | _callback(state);
|
118 | 132 | }
|
119 | 133 |
|
120 | 134 | public void Dispose()
|
121 | 135 | {
|
122 |
| - _subchannel._stateChangedRegistrations.Remove(this); |
| 136 | + if (_subchannel._stateChangedRegistrations.Remove(this)) |
| 137 | + { |
| 138 | + SubchannelLog.StateChangedRegistrationRemoved(_subchannel._logger, _subchannel.Id, RegistrationId); |
| 139 | + } |
123 | 140 | }
|
124 | 141 | }
|
125 | 142 |
|
@@ -348,6 +365,10 @@ internal void RaiseStateChanged(ConnectivityState state, Status status)
|
348 | 365 | registration.Invoke(subchannelState);
|
349 | 366 | }
|
350 | 367 | }
|
| 368 | + else |
| 369 | + { |
| 370 | + SubchannelLog.NoStateChangedRegistrations(_logger, Id); |
| 371 | + } |
351 | 372 | }
|
352 | 373 |
|
353 | 374 | /// <inheritdocs />
|
@@ -379,6 +400,11 @@ public IReadOnlyList<BalancerAddress> GetAddresses()
|
379 | 400 | public void Dispose()
|
380 | 401 | {
|
381 | 402 | UpdateConnectivityState(ConnectivityState.Shutdown, "Subchannel disposed.");
|
| 403 | + |
| 404 | + foreach (var registration in _stateChangedRegistrations) |
| 405 | + { |
| 406 | + SubchannelLog.StateChangedRegistrationRemoved(_logger, Id, registration.RegistrationId); |
| 407 | + } |
382 | 408 | _stateChangedRegistrations.Clear();
|
383 | 409 |
|
384 | 410 | CancelInProgressConnect();
|
@@ -421,6 +447,21 @@ internal static class SubchannelLog
|
421 | 447 | private static readonly Action<ILogger, int, ConnectivityState, string, Exception?> _subchannelStateChanged =
|
422 | 448 | LoggerMessage.Define<int, ConnectivityState, string>(LogLevel.Debug, new EventId(11, "SubchannelStateChanged"), "Subchannel id '{SubchannelId}' state changed to {State}. Detail: '{Detail}'.");
|
423 | 449 |
|
| 450 | + private static readonly Action<ILogger, int, string, Exception?> _stateChangedRegistrationCreated = |
| 451 | + LoggerMessage.Define<int, string>(LogLevel.Trace, new EventId(12, "StateChangedRegistrationCreated"), "Subchannel id '{SubchannelId}' state changed registration '{RegistrationId}' created."); |
| 452 | + |
| 453 | + private static readonly Action<ILogger, int, string, Exception?> _stateChangedRegistrationRemoved = |
| 454 | + LoggerMessage.Define<int, string>(LogLevel.Trace, new EventId(13, "StateChangedRegistrationRemoved"), "Subchannel id '{SubchannelId}' state changed registration '{RegistrationId}' removed."); |
| 455 | + |
| 456 | + private static readonly Action<ILogger, int, string, Exception?> _executingStateChangedRegistration = |
| 457 | + LoggerMessage.Define<int, string>(LogLevel.Trace, new EventId(14, "ExecutingStateChangedRegistration"), "Subchannel id '{SubchannelId}' executing state changed registration '{RegistrationId}'."); |
| 458 | + |
| 459 | + private static readonly Action<ILogger, int, Exception?> _noStateChangedRegistrations = |
| 460 | + LoggerMessage.Define<int>(LogLevel.Trace, new EventId(15, "NoStateChangedRegistrations"), "Subchannel id '{SubchannelId}' has no state changed registrations."); |
| 461 | + |
| 462 | + private static readonly Action<ILogger, int, BalancerAddress, Exception?> _subchannelPreserved = |
| 463 | + LoggerMessage.Define<int, BalancerAddress>(LogLevel.Trace, new EventId(16, "SubchannelPreserved"), "Subchannel id '{SubchannelId}' matches address '{Address}' and is preserved."); |
| 464 | + |
424 | 465 | public static void SubchannelCreated(ILogger logger, int subchannelId, IReadOnlyList<BalancerAddress> addresses)
|
425 | 466 | {
|
426 | 467 | if (logger.IsEnabled(LogLevel.Debug))
|
@@ -479,6 +520,31 @@ public static void SubchannelStateChanged(ILogger logger, int subchannelId, Conn
|
479 | 520 | {
|
480 | 521 | _subchannelStateChanged(logger, subchannelId, state, status.Detail, status.DebugException);
|
481 | 522 | }
|
| 523 | + |
| 524 | + public static void ExecutingStateChangedRegistration(ILogger logger, int subchannelId, string registrationId) |
| 525 | + { |
| 526 | + _executingStateChangedRegistration(logger, subchannelId, registrationId, null); |
| 527 | + } |
| 528 | + |
| 529 | + public static void NoStateChangedRegistrations(ILogger logger, int subchannelId) |
| 530 | + { |
| 531 | + _noStateChangedRegistrations(logger, subchannelId, null); |
| 532 | + } |
| 533 | + |
| 534 | + public static void StateChangedRegistrationCreated(ILogger logger, int subchannelId, string registrationId) |
| 535 | + { |
| 536 | + _stateChangedRegistrationCreated(logger, subchannelId, registrationId, null); |
| 537 | + } |
| 538 | + |
| 539 | + public static void StateChangedRegistrationRemoved(ILogger logger, int subchannelId, string registrationId) |
| 540 | + { |
| 541 | + _stateChangedRegistrationRemoved(logger, subchannelId, registrationId, null); |
| 542 | + } |
| 543 | + |
| 544 | + public static void SubchannelPreserved(ILogger logger, int subchannelId, BalancerAddress address) |
| 545 | + { |
| 546 | + _subchannelPreserved(logger, subchannelId, address, null); |
| 547 | + } |
482 | 548 | }
|
483 | 549 | }
|
484 | 550 | #endif
|
0 commit comments