예제 #1
0
        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);
            }
        }
예제 #2
0
        // 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
        }
예제 #3
0
#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);
        }
예제 #4
0
        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;
            }
        }
예제 #5
0
        internal static ElementCacher GetCurrentCache()
        {
            ElementCacher c = _currentCache;

            if (c == null || c.IsObsolete())
            {
                c = RenewCache(c);
            }

            Debug.Assert(c != null);
            return(c);
        }
예제 #6
0
        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);
            }
        }