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.
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.