Es wurde versucht, einen Mutex freizugeben, der nicht im Besitz des Aufrufers war.

Neulich habe ich in einem SharePoint 2007 (MOSS) folgende Fehlermeldung erhalten.“Es wurde versucht, einen Mutex freizugeben, der nicht im Besitz des Aufrufers war. (Ausnahme von HRESULT:0x00000120)“.

Ereigniscode: 3005
Ereignismeldung: Es ist eine unbehandelte Ausnahme aufgetreten.
Ereigniszeit: 27.10.2011 10:53:34
Ereigniszeit (UTC): 27.10.2011 08:53:34
Ereignis-ID: e4a15d8d4a344d0fad29cddb014210e3
Ereignissequenz: 76
Vorkommen: 23
Ereignisdetailcode: 0  

Anwendungsinformationen:
    Anwendungsdomäne: /LM/W3SVC/1444631078/Root-1-129641789052031250
    Vertrauensebene: Full
    Virtueller Anwendungspfad: /
    Anwendungspfad: C:InetpubwwwrootwssVirtualDirectories
    Computername: MyServer  

Prozessinformationen:
    Prozess-ID: 2972
    Prozessname: w3wp.exe
    Kontoname: MyDomain/MySystemUser 

Ausnahmeinformationen:
    Ausnahmetyp: ApplicationException
    Ausnahmemeldung: Es wurde versucht, einen Mutex freizugeben,
    der nicht im Besitz des Aufrufers war. (Ausnahme von HRESULT: 0x00000120)  

Anforderungsinformationen:
    Anforderungs-URL: https://MyPortal/Seiten/default.aspx
    Anforderungspfad: Seiten/default.aspx
    Benutzerhostadresse:
    Benutzer: MyDomain/MyUser
    Ist authentifiziert: True
    Authentifizierungstyp: Negotiate
    Threadkontoname: MyDomain/MySystemUser  

Threadinformationen:
    Thread-ID: 7
    Threadkontoname: MyDomain/MySystemUser
    Identitätswechsel für: True
    Stapelüberwachung:    bei System.Threading.ReaderWriterLock.ReleaseWriterLockInternal()
   bei System.Threading.ReaderWriterLock.ReleaseWriterLock()
   bei Microsoft.SharePoint.Publishing.ThreadSafeCache`2.ReleaseWriterLock()
   bei Microsoft.SharePoint.Publishing.AclCache.LoadAllAcls(SPSite site)
   bei Microsoft.SharePoint.Publishing.PublishingHttpModule.EnableCachingIfAppropriate(Object source, EventArgs e)
   bei System.Web.HttpApplication.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
   bei System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)

Zunächst betrachten wir einmal, was ein Mutex überhaupt ist. Dazu ein schneller Blick in die MSDN Dokumentation:

„Wenn zwei oder mehr Threads gleichzeitig auf eine gemeinsam genutzte Ressource zugreifen müssen, benötigt das System einen Synchronisierungsmechanismus, der sicherstellt, dass die Ressource von jeweils nur einem Thread verwendet wird. Mutex
ist ein primitiver Synchronisierungstyp, der jeweils nur einem Thread exklusiven Zugriff auf die gemeinsam genutzte Ressource gewährt. Wenn ein Thread einen Mutex erhält, wird ein zweiter Thread, der diesen Mutex abruft, so lange angehalten, bis der erste Thread den Mutex freigibt.“

Auf den ersten Schock folgten die ersten Rettungsversuche. Zunächst habe ich den IIS des Servers sowie den Server selbst neu gestartet, beides ohne Erfolg. Als Ursache konnte ich auch den SQL Server des Portals ausschließen. Die Anzahl der Workerprozesse des IIS haben ebenfalls keinen Einfluss.

Nach einiger Suche bin ich im Blog MsSharePointTip auf diesen Eintrag von Joshua Fuente gestoßen.

Die Ursache liegt im Ausgabecache der Site Collection. Dieser unterstützt maximal 10.000 ACL (Access Control Lists). Wird dieses Limit bei aktivem Output Cache überschritten, erscheint der hier beschriebene Fehler.

Einen entsprechenden Hinweis findet sich auch in diesem Technet Artikel. Hier wird auch die Funktionsweise des Output Cache beschrieben.

Nachdem wir nun wissen, wie das Problem entsteht können wir uns an die Lösung begeben.

Schnelle Lösung

Der Ausgabecache der Site Collection muss deaktiviert werden. Dazu rufen wir die Websiteeinstellungen der Root Site Collection auf (http://<MyPortal>/_layouts/settings.aspx). Im Bereich Websitesammlungsverwaltung kann der Ausgabecache der Websitesammlung ausgeschaltet werden.

MuTex Fehlermeldung

Die Seiten sind anschließend sofort wieder erreichbar. Allerdings werden nicht alle Elemente korrekt angezeigt (Bilder fehlen auf den Seiten). Im Eventlog finden sich diese Fehlermeldungen:

Ereigniscode: 3005
Ereignismeldung: Es ist eine unbehandelte Ausnahme aufgetreten.
Ereigniszeit: 27.10.2011 11:09:20
Ereigniszeit (UTC): 27.10.2011 09:09:20
Ereignis-ID: e1b52f4722d44faabc4694c4d36d1268
Ereignissequenz: 143
Vorkommen: 15
Ereignisdetailcode: 0  

Anwendungsinformationen:
    Anwendungsdomäne: /LM/W3SVC/1444631078/Root-1-129641797726403056
    Vertrauensebene: Full
    Virtueller Anwendungspfad: /
    Anwendungspfad: C:InetpubwwwrootwssVirtualDirectories
    Computername: MyServer  

Prozessinformationen:
    Prozess-ID: 244
    Prozessname: w3wp.exe
    Kontoname: MyDomainMySystemUser  

Ausnahmeinformationen:
    Ausnahmetyp: COMException
    Ausnahmemeldung: Der Vorgang kann nicht erfolgreich beendet werden. 

Bitte versuchen Sie es erneut.  

Anforderungsinformationen:
    Anforderungs-URL: https://MyPortal/Style Library/Images/Customer/item.gif
    Anforderungspfad: /Style Library/Images/Customer/item.gif
    Benutzerhostadresse:
    Benutzer: MyDomainMySystemUser
    Ist authentifiziert: True
    Authentifizierungstyp: Negotiate
    Threadkontoname: MyDomainMySystemUser 

Threadinformationen:
    Thread-ID: 9
    Threadkontoname: MyDomainMySystemUser
    Identitätswechsel für: False
    Stapelüberwachung:    bei Microsoft.SharePoint.Library.SPRequestInternalClass.
    GetAllAclsForCurrentSite(String bstrWebUrl, Int32 lMaxAcls)
   bei Microsoft.SharePoint.Library.SPRequest.GetAllAclsForCurrentSite(String bstrWebUrl, Int32 lMaxAcls)

Die Lösung ist also noch nicht zufriedenstellend.

Endgültige Lösung

Da der Output Cache deutliche Performance Verbesserung verspricht, indem hier alle großen Objekte, die häufig angefragt werden, zwischengespeichert werden, sollte dieser wieder aktiviert werden. Es muss also ermittelt werden, wie viele Access Control Lists verwendet werden und wo diese zur Anwendung kommen. Nur so kann die Anzahl der ACLs reduziert werden.

Mittels diesem SQL Statement kann ermittelt werden, wie viele ACL’s es gibt:

SELECT SiteID, Count(ScopeID) as 'Estimate ACLs' FROM Perms GROUP BY SiteID

Hiermit lässt sich ermitteln, in welcher Website die meisten ACLs hinterlegt sind:

SELECT SiteID, webid, Count(ScopeID) as 'Estimate ACLs' FROM Perms GROUP BY SiteID, webid 

Ist die Website bekannt, kann das Query so angepasst werden, dass nur eine bestimmte Website angezeigt wird:

select  * from perms where webid = '<GUID>' 

In meinem Fall lag es an einer Liste, die über zahlreiche Listenelemente (einige tausend) verfügte. Jedes Listenelement hatte dabei eigene Berechtigungsinformationen. Nachdem die Anzahl der Listenelemente mit eigener Berechtigung reduziert wurde, war der Spuk auch schon vorbei.