2015-07-01 17 views
8

Ten błąd zaczął się sporadycznie i niewytłumaczalnie, szczególnie podczas łączenia się z naszą bazą danych stanu sesji. Tutaj jest błąd: wydajeBłąd "Uchwyt jest nieprawidłowy" podczas otwierania SqlConnection

Exception type: COMException 
    Exception message: The handle is invalid. (Exception from HRESULT: 0x80070006 (E_HANDLE)) 
    at System.Runtime.InteropServices.Marshal.ThrowExceptionForHRInternal(Int32 errorCode, IntPtr errorInfo) 
    at System.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, UInt32 waitForMultipleObjectsTimeout, Boolean allowCreate, Boolean onlyOneCheckConnection, DbConnectionOptions userOptions, DbConnectionInternal& connection) 
    at System.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, TaskCompletionSource`1 retry, DbConnectionOptions userOptions, DbConnectionInternal& connection) 
    at System.Data.ProviderBase.DbConnectionFactory.TryGetConnection(DbConnection owningConnection, TaskCompletionSource`1 retry, DbConnectionOptions userOptions, DbConnectionInternal oldConnection, DbConnectionInternal& connection) 
    at System.Data.ProviderBase.DbConnectionInternal.TryOpenConnectionInternal(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource`1 retry, DbConnectionOptions userOptions) 
    at System.Data.SqlClient.SqlConnection.TryOpenInner(TaskCompletionSource`1 retry) 
    at System.Data.SqlClient.SqlConnection.TryOpen(TaskCompletionSource`1 retry) 
    at System.Data.SqlClient.SqlConnection.Open() 

możliwie związane błąd czasami w oknach podglądu zdarzeń:

Application: w3wp.exe 
Framework Version: v4.0.30319 
Description: The process was terminated due to an unhandled exception. 
Exception Info: System.Threading.SemaphoreFullException 
Stack: 
    at System.Threading.Semaphore.Release(Int32) 
    at System.Data.ProviderBase.DbConnectionPool.CleanupCallback(System.Object) 
    at System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean) 
    at System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean) 
    at System.Threading.TimerQueueTimer.CallCallback() 
    at System.Threading.TimerQueueTimer.Fire() 
    at System.Threading.TimerQueue.FireNextTimers() 

EDIT: inny smak wyjątkiem jest następujący:

Exception Type: System.ComponentModel.Win32Exception 
Error message: An operation was attempted on something that is not a socket 
No Stack Trace Available 
Exception Type: System.Data.SqlClient.SqlException 
Error message: A transport-level error has occurred when sending the request to the server. (provider: TCP Provider, error: 0 - An operation was attempted on something that is not a socket.) 
at System.Data.SqlClient.TdsParser.TdsExecuteRPC(_SqlRPC[] rpcArray, Int32 timeout, Boolean inSchema, SqlNotificationRequest notificationRequest, TdsParserStateObject stateObj, Boolean isCommandProc, Boolean sync, TaskCompletionSource`1 completion, Int32 startRpc, Int32 startParam) 
at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite, SqlDataReader ds) 
at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean asyncWrite) 
at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method) 
at System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method) 
at System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior) 
at System.Web.SessionState.SqlSessionStateStore.SqlExecuteReaderWithRetry(SqlCommand cmd, CommandBehavior cmdBehavior) 
Exception Type: System.Web.HttpException 
Error message: Unable to connect to SQL Server session database. 
at System.Web.SessionState.SqlSessionStateStore.SqlExecuteReaderWithRetry(SqlCommand cmd, CommandBehavior cmdBehavior) 
at System.Web.SessionState.SqlSessionStateStore.DoGet(HttpContext context, String id, Boolean getExclusive, Boolean& locked, TimeSpan& lockAge, Object& lockId, SessionStateActions& actionFlags) 
at System.Web.SessionState.SqlSessionStateStore.GetItem(HttpContext context, String id, Boolean& locked, TimeSpan& lockAge, Object& lockId, SessionStateActions& actionFlags) 
at System.Web.SessionState.SessionStateModule.GetSessionStateItem() 
at System.Web.SessionState.SessionStateModule.BeginAcquireState(Object source, EventArgs e, AsyncCallback cb, Object extraData) 
at System.Web.HttpApplication.AsyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() 
at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) 

może ktoś zasugerować:

  1. Co to oznacza oznaczać?
  2. Co może spowodować to (jest to w aplikacji, która działa bardzo długo, bez poważniejszych zmian w infrastrukturze, zanim to się zaczęło)?
  3. Co można zrobić, aby go rozwiązać?
+0

Jak duży jest twój basen połączenia z bazą danych? Czy możesz spojrzeć na serwer DB, aby sprawdzić, ile ma aktywnych połączeń? – Brian

+0

Podczas przekraczania granicy .Net można uzyskać zrzut wyjątku za pomocą adplus i przeanalizować wątki za pomocą windbg, z poprawnymi plikami pdb będzie jasno wyjaśniał pochodzenie wyjątku. Przeważnie problem dotyczy kodu niezarządzanego. –

+0

@Brian Obecnie istnieje ~ 260 połączeń. Nie robimy nic, aby przesłonić rozmiar puli połączeń, więc domyślam się, że mamy domyślną? – ChaseMedallion

Odpowiedz

7

Jak się okazało, śledziliśmy błąd, aby usunąć deserializację Token Anulowania za pomocą Json.Net.

Podstawowy problem występuje, gdy kod nadal próbuje użyć uchwytu systemu operacyjnego, który został zwolniony. Oczywiście może się to zdarzyć, gdy twój kod działa bezpośrednio z uchwytami. Nasz kod tego nie robi, ale okazuje się, że może się to zdarzyć z Json.Net. Oto jak:

Mieliśmy klasy następująco:

public class MyClass 
{ 
    ... 
} 

// in one part of the code, this class was serialized & deserialized using Json.Net: 
JsonConvert.SerializeObject(...); 
JsonConvert.DeserializeObject<MyClass>(...); 

problem wystąpił, gdy ktoś dodaje obiekt do MojaKlasa typu CancellationToken:

public class MyClass 
{ 
    ... 
    public CancellationToken Token { get; set; } 
} 

tu jest problem. Kiedy w odcinkach, o CancellationToken wygląda następująco:

{"IsCancellationRequested":false,"CanBeCanceled":true,"WaitHandle":{"Handle":{"value":1508},"SafeWaitHandle":{"IsInvalid":false,"IsClosed":false}}} 

Zauważ, że robi tak leniwy stwarza własności WaitHandle tokenu i serializes Wartość tego uchwytu bazowego OS (1508).

Kiedy deserializujemy token, Json.Net rozpocznie się od new CancellationToken() (odpowiednik CancellationToken.None). Następnie zostanie wypełniona właściwość Handle tego tokena WaitHandle przy użyciu zapisanej wartości IntPtr. Jednym z oczywistych sposobów, w jaki powoduje to, że coś idzie nie tak, jest to, że domyślna wartość WaitHandle w CancellationToken wskazuje teraz na nieprawidłowy uchwyt. Jednak większy problem polega na tym, że aktualizacja uchwytu powoduje oderwanie oryginalnego urządzenia SafeHandle od WaitHandle, co pozwala mu uruchomić finalizator i oczyścić go.Można wtedy paść ofiarą następujący zestaw zdarzeń:

  1. Uchwyt 123 jest przeznaczonych do zbiorczej połączenia z bazą danych
  2. deserializacji przypisuje obsłużyć 123 do domyślnej Rezygnacja tokena WaitHandle
  3. Drugi deserializacji przypisuje nowy uchwyt do domyślnej wartości Rezygnacja tokena WaitHandle
  4. tras śmieciarza i finalizuje uwalnianego 123 bezpieczną wartość uchwytu
  5. połączenie z bazą danych wskazuje teraz na nieprawidłowy uchwyt

Oto niektóre kod, który celowo powiela problem za pomocą FileStream:

// serialize 2 tokens 
var source = new CancellationTokenSource(); 
var serialized = JsonConvert.SerializeObject(source.Token); 
var serialized2 = JsonConvert.SerializeObject(new CancellationTokenSource().Token); 
var handle = source.Token.WaitHandle.Handle; 
source.Dispose(); // releases source's handle 

// spin until the OS gives us back that same handle as 
// a file handle 
FileStream fileStream; 
while (true) 
{ 
    fileStream = new FileStream(Path.GetTempFileName(), FileMode.OpenOrCreate); 
    if (fileStream.Handle == handle) { break; } 
} 

// deserialize both tokens, thus releasing the conflicting handle 
var deserialized = JsonConvert.DeserializeObject<CancellationToken>(serialized); 
var deserialized2 = JsonConvert.DeserializeObject<CancellationToken>(serialized2); 

GC.Collect(); 
GC.WaitForPendingFinalizers(); 

fileStream.WriteByte(1); 
fileStream.Flush(); // fails with IOException "The handle is invalid" 
+0

Właśnie przyszedł tutaj, czytając listę elementów JSON.Net (jestem obserwatorem repo). Dzięki za udostępnienie rozwiązania :) To debugowanie tego typu rzeczy - połączenia z serwerem SQL rozbijają się losowo i zdarza się, że używasz JSON.Net do deserializacji Token Anulowania - gdzie utrzymywanie tego rodzaju problemu w tylnej kieszeni może zaoszczędzić niezliczoną ilość godzin! –

0

Możesz spróbować wejść do Menedżera konfiguracji SQL Server i wyłączyć jeden lub więcej protokołów i sprawdzić, czy to pomaga. Jeśli serwer SQL i klient znajdują się na tym samym komputerze, być może korzystasz z pamięci współużytkowanej, a system wyczerpał pamięć sterty dla uchwytów. Spróbuj wymusić połączenia, aby korzystać z protokołu TCP i sprawdź, czy ten sam problem występuje.

+0

W tym przypadku SQL Server i kod aplikacji znajdują się na różnych komputerach. Czy to wyklucza taką możliwość? Czy inny błąd przecięcia może powodować ten błąd? – ChaseMedallion

+0

Tak i nie. Zauważyłem, że część błędu wspomniała o gnieździe, które jest interfejsem Windows do TCP/IP. Gniazda wyglądają podobnie do plików w systemie operacyjnym, więc nadal może to być problem z stertą na pulpicie. Może spróbuj uruchomić pulę aplikacji IIS jako inny użytkownik. – Wonko

Powiązane problemy