コード例 #1
0
        public override async Task ExecuteAfterTransactionCompletionAsync(bool success, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();
            // NH Different behavior: to support unlocking collections from the cache.(r3260)

            CacheKey ck = Session.GenerateCacheKey(await(GetKeyAsync(cancellationToken)).ConfigureAwait(false), Persister.KeyType, Persister.Role);

            if (success)
            {
                // we can't disassemble a collection if it was uninitialized
                // or detached from the session
                if (Collection.WasInitialized && Session.PersistenceContext.ContainsCollection(Collection))
                {
                    CollectionCacheEntry entry = await(CollectionCacheEntry.CreateAsync(Collection, Persister, cancellationToken)).ConfigureAwait(false);
                    bool put = await(Persister.Cache.AfterUpdateAsync(ck, entry, null, Lock, cancellationToken)).ConfigureAwait(false);

                    if (put && Session.Factory.Statistics.IsStatisticsEnabled)
                    {
                        Session.Factory.StatisticsImplementor.SecondLevelCachePut(Persister.Cache.RegionName);
                    }
                }
            }
            else
            {
                await(Persister.Cache.ReleaseAsync(ck, Lock, cancellationToken)).ConfigureAwait(false);
            }
        }
コード例 #2
0
        /// <summary> Try to initialize a collection from the cache</summary>
        private async Task <bool> InitializeCollectionFromCacheAsync(object id, ICollectionPersister persister, IPersistentCollection collection, ISessionImplementor source, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();

            if (!(source.EnabledFilters.Count == 0) && persister.IsAffectedByEnabledFilters(source))
            {
                log.Debug("disregarding cached version (if any) of collection due to enabled filters ");
                return(false);
            }

            bool useCache = persister.HasCache && source.CacheMode.HasFlag(CacheMode.Get);

            if (!useCache)
            {
                return(false);
            }
            else
            {
                ISessionFactoryImplementor factory = source.Factory;

                CacheKey ck = source.GenerateCacheKey(id, persister.KeyType, persister.Role);
                object   ce = await(persister.Cache.GetAsync(ck, source.Timestamp, cancellationToken)).ConfigureAwait(false);

                if (factory.Statistics.IsStatisticsEnabled)
                {
                    if (ce == null)
                    {
                        factory.StatisticsImplementor.SecondLevelCacheMiss(persister.Cache.RegionName);
                    }
                    else
                    {
                        factory.StatisticsImplementor.SecondLevelCacheHit(persister.Cache.RegionName);
                    }
                }

                if (ce == null)
                {
                    log.Debug("Collection cache miss: {0}", ck);
                }
                else
                {
                    log.Debug("Collection cache hit: {0}", ck);
                }

                if (ce == null)
                {
                    return(false);
                }
                else
                {
                    IPersistenceContext persistenceContext = source.PersistenceContext;

                    CollectionCacheEntry cacheEntry = (CollectionCacheEntry)persister.CacheEntryStructure.Destructure(ce, factory);
                    await(cacheEntry.AssembleAsync(collection, persister, persistenceContext.GetCollectionOwner(id, persister), cancellationToken)).ConfigureAwait(false);

                    persistenceContext.GetCollectionEntry(collection).PostInitialize(collection);
                    return(true);
                }
            }
        }
コード例 #3
0
        public override void AfterTransactionCompletion(bool success)
        {
            // NH Different behavior: to support unlocking collections from the cache.(r3260)
            if (Persister.HasCache)
            {
                CacheKey ck = new CacheKey(Key, Persister.KeyType, Persister.Role, Session.EntityMode, Session.Factory);

                if (success)
                {
                    // we can't disassemble a collection if it was uninitialized
                    // or detached from the session
                    if (Collection.WasInitialized && Session.PersistenceContext.ContainsCollection(Collection))
                    {
                        CollectionCacheEntry entry = new CollectionCacheEntry(Collection, Persister);
                        bool put = Persister.Cache.AfterUpdate(ck, entry, null, Lock);

                        if (put && Session.Factory.Statistics.IsStatisticsEnabled)
                        {
                            Session.Factory.StatisticsImplementor.SecondLevelCachePut(Persister.Cache.RegionName);
                        }
                    }
                }
                else
                {
                    Persister.Cache.Release(ck, Lock);
                }
            }
        }
コード例 #4
0
        protected void AssertEqual(CollectionCacheEntry original, CollectionCacheEntry copy)
        {
            Assert.That(copy.State, Is.TypeOf(original.State.GetType()));

            var originalArray = original.State;
            var copyArray     = copy.State;

            for (var i = 0; i < copyArray.Length; i++)
            {
                if (originalArray[i] == null)
                {
                    Assert.That(copyArray[i], Is.Null);
                    continue;
                }

                Assert.That(copyArray[i], Is.TypeOf(originalArray[i].GetType()));
                if (originalArray[i] is AnyType.ObjectTypeCacheEntry originalAnyType)
                {
                    var copyAnyType = (AnyType.ObjectTypeCacheEntry)copyArray[i];
                    AssertEqual(originalAnyType, copyAnyType);
                }
                else
                {
                    Assert.That(copyArray[i], Is.EqualTo(originalArray[i]));
                }
            }
        }
コード例 #5
0
        /// <summary> Try to initialize a collection from the cache</summary>
        private bool InitializeCollectionFromCache(object id, ICollectionPersister persister, IPersistentCollection collection, ISessionImplementor source)
        {
            if (!(source.EnabledFilters.Count == 0) && persister.IsAffectedByEnabledFilters(source))
            {
                log.Debug("disregarding cached version (if any) of collection due to enabled filters ");
                return(false);
            }

            bool useCache = persister.HasCache && ((source.CacheMode & CacheMode.Get) == CacheMode.Get);

            if (!useCache)
            {
                return(false);
            }
            else
            {
                ISessionFactoryImplementor factory = source.Factory;

                CacheKey ck = new CacheKey(id, persister.KeyType, persister.Role, source.EntityMode, factory);
                object   ce = persister.Cache.Get(ck, source.Timestamp);

                if (factory.Statistics.IsStatisticsEnabled)
                {
                    if (ce == null)
                    {
                        factory.StatisticsImplementor.SecondLevelCacheMiss(persister.Cache.RegionName);
                    }
                    else
                    {
                        factory.StatisticsImplementor.SecondLevelCacheHit(persister.Cache.RegionName);
                    }
                }

                if (ce == null)
                {
                    log.DebugFormat("Collection cache miss: {0}", ck);
                }
                else
                {
                    log.DebugFormat("Collection cache hit: {0}", ck);
                }

                if (ce == null)
                {
                    return(false);
                }
                else
                {
                    IPersistenceContext persistenceContext = source.PersistenceContext;

                    CollectionCacheEntry cacheEntry = (CollectionCacheEntry)persister.CacheEntryStructure.Destructure(ce, factory);
                    cacheEntry.Assemble(collection, persister, persistenceContext.GetCollectionOwner(id, persister));

                    persistenceContext.GetCollectionEntry(collection).PostInitialize(collection);
                    return(true);
                }
            }
        }
コード例 #6
0
        public void SecondLevelCachedCollectionsFiltering()
        {
            TestData testData = new TestData(this);

            testData.Prepare();

            ISession session = OpenSession();

            // Force a collection into the second level cache, with its non-filtered elements
            Salesperson sp = (Salesperson)session.Load(typeof(Salesperson), testData.steveId);

            NHibernateUtil.Initialize(sp.Orders);
            ICollectionPersister persister = ((ISessionFactoryImplementor)sessions)
                                             .GetCollectionPersister(typeof(Salesperson).FullName + ".Orders");

            Assert.IsTrue(persister.HasCache, "No cache for collection");
            CacheKey cacheKey =
                new CacheKey(testData.steveId, persister.KeyType, persister.Role, EntityMode.Poco, (ISessionFactoryImplementor)sessions);
            CollectionCacheEntry cachedData = (CollectionCacheEntry)persister.Cache.Cache.Get(cacheKey);

            Assert.IsNotNull(cachedData, "collection was not in cache");

            session.Close();

            session = OpenSession();
            session.EnableFilter("fulfilledOrders").SetParameter("asOfDate", testData.lastMonth);
            sp = (Salesperson)session.CreateQuery("from Salesperson as s where s.id = :id")
                 .SetInt64("id", testData.steveId)
                 .UniqueResult();
            Assert.AreEqual(1, sp.Orders.Count, "Filtered-collection not bypassing 2L-cache");

            CollectionCacheEntry cachedData2 = (CollectionCacheEntry)persister.Cache.Cache.Get(cacheKey);

            Assert.IsNotNull(cachedData2, "collection no longer in cache!");
            Assert.AreSame(cachedData, cachedData2, "Different cache values!");

            session.Close();

            session = OpenSession();
            session.EnableFilter("fulfilledOrders").SetParameter("asOfDate", testData.lastMonth);
            sp = (Salesperson)session.Load(typeof(Salesperson), testData.steveId);
            Assert.AreEqual(1, sp.Orders.Count, "Filtered-collection not bypassing 2L-cache");

            session.Close();

            // Finally, make sure that the original cached version did not get over-written
            session = OpenSession();
            sp      = (Salesperson)session.Load(typeof(Salesperson), testData.steveId);
            Assert.AreEqual(2, sp.Orders.Count, "Actual cached version got over-written");

            session.Close();
            testData.Release();
        }
コード例 #7
0
        /// <summary> Add the collection to the second-level cache </summary>
        /// <param name="lce">The entry representing the collection to add </param>
        /// <param name="persister">The persister </param>
        /// <param name="cancellationToken">A cancellation token that can be used to cancel the work</param>
        private async Task AddCollectionToCacheAsync(LoadingCollectionEntry lce, ICollectionPersister persister, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();
            ISessionImplementor        session = LoadContext.PersistenceContext.Session;
            ISessionFactoryImplementor factory = session.Factory;

            if (log.IsDebugEnabled())
            {
                log.Debug("Caching collection: {0}", MessageHelper.CollectionInfoString(persister, lce.Collection, lce.Key, session));
            }

            if (!(session.EnabledFilters.Count == 0) && persister.IsAffectedByEnabledFilters(session))
            {
                // some filters affecting the collection are enabled on the session, so do not do the put into the cache.
                log.Debug("Refusing to add to cache due to enabled filters");
                // todo : add the notion of enabled filters to the CacheKey to differentiate filtered collections from non-filtered;
                //      but CacheKey is currently used for both collections and entities; would ideally need to define two separate ones;
                //      currently this works in conjunction with the check on
                //      DefaultInitializeCollectionEventHandler.initializeCollectionFromCache() (which makes sure to not read from
                //      cache with enabled filters).
                return;                 // EARLY EXIT!!!!!
            }

            IComparer versionComparator;
            object    version;

            if (persister.IsVersioned)
            {
                versionComparator = persister.OwnerEntityPersister.VersionType.Comparator;
                object collectionOwner = LoadContext.PersistenceContext.GetCollectionOwner(lce.Key, persister);
                if (collectionOwner == null)
                {
                    return;
                }
                version = LoadContext.PersistenceContext.GetEntry(collectionOwner).Version;
            }
            else
            {
                version           = null;
                versionComparator = null;
            }

            CollectionCacheEntry entry    = new CollectionCacheEntry(lce.Collection, persister);
            CacheKey             cacheKey = session.GenerateCacheKey(lce.Key, persister.KeyType, persister.Role);
            bool put = await(persister.Cache.PutAsync(cacheKey, persister.CacheEntryStructure.Structure(entry),
                                                      session.Timestamp, version, versionComparator,
                                                      factory.Settings.IsMinimalPutsEnabled && session.CacheMode != CacheMode.Refresh, cancellationToken)).ConfigureAwait(false);

            if (put && factory.Statistics.IsStatisticsEnabled)
            {
                factory.StatisticsImplementor.SecondLevelCachePut(persister.Cache.RegionName);
            }
        }
コード例 #8
0
    public static void SaveCollection <T>(string sKey, List <T> colItems) where T : IUniqueIdActiveRecord
    {
        CollectionCacheEntry objCacheEntry = new CollectionCacheEntry();

        objCacheEntry.Key        = sKey;
        objCacheEntry.CacheEntry = DateTime.Now;
        objCacheEntry.LastAccess = DateTime.Now;
        objCacheEntry.LastUpdate = DateTime.Now;
        objCacheEntry.Collection = CloneCollection(colItems);
        lock (GetKeyLock(sKey))
        {
            _htCollectionCache[sKey] = objCacheEntry;
        }
    }
コード例 #9
0
    public static void SaveCollection(string sKey, List <Guid> colIDs)
    {
        CollectionCacheEntry objCacheEntry = new CollectionCacheEntry();

        objCacheEntry.Key        = sKey;
        objCacheEntry.CacheEntry = DateTime.Now;
        objCacheEntry.LastAccess = DateTime.Now;
        objCacheEntry.LastUpdate = DateTime.Now;
        objCacheEntry.Collection = CloneCollection(colIDs);
        lock (GetKeyLock(sKey))
        {
            _htCollectionCache[sKey] = objCacheEntry;
        }
    }
        private async Task <bool> AssembleAsync(
            CacheKey ck, object ce, ICollectionPersister persister, ISessionImplementor source,
            IPersistentCollection collection, object collectionKey, bool alterStatistics, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();
            ISessionFactoryImplementor factory = source.Factory;

            if (factory.Statistics.IsStatisticsEnabled && alterStatistics)
            {
                if (ce == null)
                {
                    factory.StatisticsImplementor.SecondLevelCacheMiss(persister.Cache.RegionName);
                }
                else
                {
                    factory.StatisticsImplementor.SecondLevelCacheHit(persister.Cache.RegionName);
                }
            }

            if (ce == null)
            {
                log.Debug("Collection cache miss: {0}", ck);
            }
            else
            {
                log.Debug("Collection cache hit: {0}", ck);
            }

            if (ce == null)
            {
                return(false);
            }
            else
            {
                IPersistenceContext persistenceContext = source.PersistenceContext;

                CollectionCacheEntry cacheEntry = (CollectionCacheEntry)persister.CacheEntryStructure.Destructure(ce, factory);
                await(cacheEntry.AssembleAsync(collection, persister, persistenceContext.GetCollectionOwner(collectionKey, persister), cancellationToken)).ConfigureAwait(false);

                persistenceContext.GetCollectionEntry(collection).PostInitialize(collection, persistenceContext);

                if (collection.HasQueuedOperations)
                {
                    collection.ApplyQueuedOperations();
                }
                return(true);
            }
        }
コード例 #11
0
 public static void UpdateItem <T>(string sKey, T objItem)  where T : IUniqueIdActiveRecord
 {
     lock (GetKeyLock(sKey))
     {
         if (_htCollectionCache.ContainsKey(sKey) == true)
         {
             CollectionCacheEntry objCacheEntry = _htCollectionCache[sKey];
             List <T>             colItems      = (List <T>)objCacheEntry.Collection;
             colItems.RemoveAll(o => o.Id == objItem.Id);
             colItems.Add(objItem);
             objCacheEntry.Collection = colItems;
             objCacheEntry.LastAccess = DateTime.Now;
             objCacheEntry.LastUpdate = DateTime.Now;
         }
     }
 }
コード例 #12
0
        public async Task SecondLevelCachedCollectionsFilteringAsync()
        {
            var persister = Sfi
                            .GetCollectionPersister(typeof(Salesperson).FullName + ".Orders");
            var cacheKey =
                new CacheKey(testData.steveId, persister.KeyType, persister.Role, Sfi);
            CollectionCacheEntry cachedData;

            using (var session = OpenSession())
            {
                // Force a collection into the second level cache, with its non-filtered elements
                var sp = (Salesperson)await(session.LoadAsync(typeof(Salesperson), testData.steveId));
                await(NHibernateUtil.InitializeAsync(sp.Orders));
                Assert.IsTrue(persister.HasCache, "No cache for collection");
                cachedData = (CollectionCacheEntry)await(persister.Cache.Cache.GetAsync(cacheKey, CancellationToken.None));
                Assert.IsNotNull(cachedData, "collection was not in cache");
            }

            using (var session = OpenSession())
            {
                session.EnableFilter("fulfilledOrders").SetParameter("asOfDate", testData.lastMonth);
                var sp = (Salesperson)await(session.CreateQuery("from Salesperson as s where s.id = :id")
                                            .SetInt64("id", testData.steveId)
                                            .UniqueResultAsync());
                Assert.AreEqual(1, sp.Orders.Count, "Filtered-collection not bypassing 2L-cache");

                CollectionCacheEntry cachedData2 = (CollectionCacheEntry)await(persister.Cache.Cache.GetAsync(cacheKey, CancellationToken.None));
                Assert.IsNotNull(cachedData2, "collection no longer in cache!");
                Assert.AreSame(cachedData, cachedData2, "Different cache values!");
            }

            using (var session = OpenSession())
            {
                session.EnableFilter("fulfilledOrders").SetParameter("asOfDate", testData.lastMonth);
                var sp = (Salesperson)await(session.LoadAsync(typeof(Salesperson), testData.steveId));
                Assert.AreEqual(1, sp.Orders.Count, "Filtered-collection not bypassing 2L-cache");
            }

            // Finally, make sure that the original cached version did not get over-written
            using (var session = OpenSession())
            {
                var sp = (Salesperson)await(session.LoadAsync(typeof(Salesperson), testData.steveId));
                Assert.AreEqual(2, sp.Orders.Count, "Actual cached version got over-written");
            }
        }
コード例 #13
0
    private static List <T> GetCollection <T>(string sKey) where T : IUniqueIdActiveRecord
    {
        List <T> objReturnCollection = null;

        if (_htCollectionCache.Keys.Contains(sKey) == true)
        {
            CollectionCacheEntry objCacheEntry = null;
            lock (GetKeyLock(sKey))
            {
                objCacheEntry            = _htCollectionCache[sKey];
                objCacheEntry.LastAccess = DateTime.Now;
            }
            if (objCacheEntry.Collection != null && objCacheEntry.Collection is List <T> )
            {
                objReturnCollection = CloneCollection <T>((List <T>)objCacheEntry.Collection);
            }
        }
        return(objReturnCollection);
    }
        private bool Assemble(CacheKey ck, object ce, ICollectionPersister persister, ISessionImplementor source,
                              IPersistentCollection collection, object id, bool alterStatistics)
        {
            ISessionFactoryImplementor factory = source.Factory;

            if (factory.Statistics.IsStatisticsEnabled && alterStatistics)
            {
                if (ce == null)
                {
                    factory.StatisticsImplementor.SecondLevelCacheMiss(persister.Cache.RegionName);
                }
                else
                {
                    factory.StatisticsImplementor.SecondLevelCacheHit(persister.Cache.RegionName);
                }
            }

            if (ce == null)
            {
                log.Debug("Collection cache miss: {0}", ck);
            }
            else
            {
                log.Debug("Collection cache hit: {0}", ck);
            }

            if (ce == null)
            {
                return(false);
            }
            else
            {
                IPersistenceContext persistenceContext = source.PersistenceContext;

                CollectionCacheEntry cacheEntry = (CollectionCacheEntry)persister.CacheEntryStructure.Destructure(ce, factory);
                cacheEntry.Assemble(collection, persister, persistenceContext.GetCollectionOwner(id, persister));

                persistenceContext.GetCollectionEntry(collection).PostInitialize(collection, persistenceContext);
                return(true);
            }
        }
コード例 #15
0
        private void CheckCollectionCacheEntry(CollectionCacheEntry original, CollectionCacheEntry copy)
        {
            Assert.That(copy.State, Is.TypeOf(original.State.GetType()));

            var originalArray = original.State;
            var copyArray     = copy.State;

            for (var i = 0; i < copyArray.Length; i++)
            {
                Assert.That(copyArray[i], Is.TypeOf(originalArray[i].GetType()));
                if (originalArray[i] is AnyType.ObjectTypeCacheEntry originalAnyType)
                {
                    var copyAnyType = (AnyType.ObjectTypeCacheEntry)copyArray[i];
                    CheckObjectTypeCacheEntry(originalAnyType, copyAnyType);
                }
                else
                {
                    Assert.That(copyArray[i], Is.EqualTo(originalArray[i]));
                }
            }
        }
コード例 #16
0
    public static List <Guid> FetchAndCache(string sKey, Func <List <Guid> > fGetCollectionDelegate)
    {
        List <Guid> colIds = new List <Guid>();

        lock (GetKeyLock(sKey))
        {
            if (_htCollectionCache.Keys.Contains(sKey) == true)
            {
                CollectionCacheEntry objCacheEntry = _htCollectionCache[sKey];
                colIds = (List <Guid>)objCacheEntry.Collection;
                objCacheEntry.LastAccess = DateTime.Now;
            }
            else
            {
                colIds = fGetCollectionDelegate();
                SaveCollection(sKey, colIds);
            }
        }
        List <Guid> colReturnIds = CloneCollection(colIds);

        return(colReturnIds);
    }
コード例 #17
0
    public static List <T> FetchAndCache <T>(string sKey, Func <List <T> > fGetCollectionDelegate) where T : IUniqueIdActiveRecord
    {
        List <T> colItems = new List <T>();

        lock (GetKeyLock(sKey))
        {
            if (_htCollectionCache.Keys.Contains(sKey) == true)
            {
                CollectionCacheEntry objCacheEntry = _htCollectionCache[sKey];
                colItems = (List <T>)objCacheEntry.Collection;
                objCacheEntry.LastAccess = DateTime.Now;
            }
            else
            {
                colItems = fGetCollectionDelegate();
                SaveCollection <T>(sKey, colItems);
            }
        }
        List <T> objReturnCollection = CloneCollection <T>(colItems);

        return(objReturnCollection);
    }
コード例 #18
0
 public static void UpdateCollection <T>(string sKey, List <T> colItems) where T : IUniqueIdActiveRecord
 {
     lock (GetKeyLock(sKey))
     {
         if (_htCollectionCache.ContainsKey(sKey) == true)
         {
             CollectionCacheEntry objCacheEntry = _htCollectionCache[sKey];
             objCacheEntry.LastAccess = DateTime.Now;
             objCacheEntry.LastUpdate = DateTime.Now;
             objCacheEntry.Collection = new List <T>();
             //Clone the collection before insertion to ensure it can't be touched
             foreach (T objItem in colItems)
             {
                 objCacheEntry.Collection.Add(objItem);
             }
             _htCollectionCache[sKey] = objCacheEntry;
         }
         else
         {
             SaveCollection <T>(sKey, colItems);
         }
     }
 }