internal static ElementCacher RenewCache(ElementCacher oldCache) { lock (_clientCacheLock) { // If another thread has already updated the cache, we don't need to renew. if (_currentCache != oldCache) { return(_currentCache); } // The size of the new cache. int newCacheSize; // Whether to copy the contents of the old cache into the new cache. bool copyOldCache = false; if (oldCache == null) { newCacheSize = FontCacheConstants.InitialLocalCacheSize; } else { newCacheSize = oldCache.MaxCacheSize * FontCacheConstants.CacheGrowthFactor; if (newCacheSize > FontCacheConstants.MaximumLocalCacheSize) { newCacheSize = FontCacheConstants.MaximumLocalCacheSize; } else { copyOldCache = true; } } // Current client cache either doesn't exist or it is obsolete, // create a new one. FileMapping m = new FileMapping(); m.Create(null, newCacheSize); ElementCacher c = new ElementCacher(m, true, false); if (copyOldCache) { // Copy the bits from the old cache. Debug.Assert(newCacheSize > oldCache.CurrentSize); c.InitFromPreviousCache(oldCache, newCacheSize); } // Flush the cache before exposing it, so that clients have a consistent view of it Thread.MemoryBarrier(); _currentCache = c; if (oldCache != null) { oldCache.MarkObsolete(); } return(c); } }
// Disable Presharp warning about Dispose() not being called on the disposable FileMapping object. // This is by design, because lifetime of m extends this function - the pointer is passed to ElementCacher ctor. #pragma warning disable 6518 private static ElementCacher OpenServerCache(string serverSectionName) { // Disable Presharp warning about empty catch body. // This is by design, as we should continue even in case of server connection failures. #pragma warning disable 6502 try { // open cache FileMapping m = new FileMapping(); m.OpenSection(serverSectionName); ElementCacher c = new ElementCacher(m, false, true); if (c.VersionUpToDate()) { _serverCache = c; return(c); } } // This can be thrown when for some reason we cannot connect to the server. catch (IOException) { } return(null); #pragma warning restore 6502 }
#pragma warning restore 6518 internal static void SaveNativeCache(ElementCacher c, IList <ElementCacher> nativeCaches) { int count = nativeCaches.Count; if (count > 0 && c == nativeCaches[count - 1]) { return; // it's already stored, so don't bother } nativeCaches.Add(c); }
internal void InitFromPreviousCache(ElementCacher oldCache, int newCacheSize) { // We need to lock the old cache to make sure it's CurrentSize is not updated in the middle of the copy. lock (oldCache.Lock) { InitFromCacheImage(oldCache.Mapping); // Reset max cache size to the new size, because InitFromCacheImage overwrote it. MaxCacheSize = newCacheSize; } }
internal static ElementCacher GetCurrentCache() { ElementCacher c = _currentCache; if (c == null || c.IsObsolete()) { c = RenewCache(c); } Debug.Assert(c != null); return(c); }
internal static ElementCacher GetServerCache() { // the current cache is up to date if (_serverCache != null && !_serverCache.IsObsolete()) { return(_serverCache); } // we know that connecting to the service will likely fail if (!_tryToConnect) { return(_serverCache); } lock (_sharedCacheLock) { // repeat the checks from above within the lock if (_serverCache != null && !_serverCache.IsObsolete()) { return(_serverCache); } if (!_tryToConnect) { return(_serverCache); } if (_fc == null) { _fc = FontCacheConfig.Current; _ipcMngr = new IPCCacheManager(_fc); } int errorCode = 0; string serverSectionName = null; if (_serverCache != null) { // Server port is open, but the cache is obsolete. Get a new section name. Debug.Assert(_serverCache.IsObsolete()); Debug.Assert(_ipcMngr.IsConnected); Debug.WriteLine("Retrieving cache name from server"); //Ignore error code, just let serverSectionName be null if error. serverSectionName = _ipcMngr.GetServerSectionName(_fc.SecondConnectTimeout, out errorCode); } else { //Connect to the server and get the server cache int[] timeouts = { _fc.FirstConnectTimeout, _fc.SecondConnectTimeout }; for (int i = 0; ; i++) { //If we had an old connection lying around close it and get rid of it if (_ipcMngr.IsConnected) { _ipcMngr.CloseConnection(); } //Get the server name. If we're not connected, connect. serverSectionName = _ipcMngr.GetServerSectionName(timeouts[i], out errorCode); //If we succeeded, we can stop here if (serverSectionName != null) { break;//success } if ((i + 1) >= timeouts.Length) { break;//all attempts exhausted - give up } //If we failed, it could be because the font cache service isn't running, //so try to start it now. Don't waste time with this if we fail for another reason. if (errorCode == _ipcMngr.ServerNotFoundErrorCode) { if (_fc.RestartServiceOnError) { if (!ServiceOps.StartServiceWithTimeout(BuildInfo.FontCacheServiceName, _fc.ServerStartTimeout)) { //could not start service - give up break; } } else { break;//restart service option not set } } else { break;//no point in continuing } } } if (serverSectionName == null) { // keep using the old cache if the new name can't be obtained (or null if there is no old cache) _ipcMngr.CloseConnection(); _tryToConnect = false; return(_serverCache); } //Attempt to open the cache. Update _serverCache if successful, //but keep using the old cache if there is an error. ElementCacher c = OpenServerCache(serverSectionName); if (c != null) { _serverCache = c; } else { // low memory conditions, don't attempt to connect, but keep using the old cache _tryToConnect = false; } return(_serverCache); } }