Example #1
0
        /// <summary> Attempts to load the entity from the second-level cache. </summary>
        /// <param name="event">The load event </param>
        /// <param name="persister">The persister for the entity being requested for load </param>
        /// <param name="options">The load options. </param>
        /// <param name="cancellationToken">A cancellation token that can be used to cancel the work</param>
        /// <returns> The entity from the second-level cache, or null. </returns>
        protected virtual async Task <object> LoadFromSecondLevelCacheAsync(LoadEvent @event, IEntityPersister persister, LoadType options, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();
            ISessionImplementor source = @event.Session;
            bool useCache = persister.HasCache && source.CacheMode.HasFlag(CacheMode.Get) &&
                            @event.LockMode.LessThan(LockMode.Read);

            if (!useCache)
            {
                return(null);
            }
            ISessionFactoryImplementor factory = source.Factory;
            var batchSize   = persister.GetBatchSize();
            var entityBatch = source.PersistenceContext.BatchFetchQueue.QueryCacheQueue
                              ?.GetEntityBatch(persister, @event.EntityId);

            if (entityBatch != null || batchSize > 1 && persister.Cache.PreferMultipleGet())
            {
                // The first item in the array is the item that we want to load
                if (entityBatch != null)
                {
                    if (entityBatch.Length == 0)
                    {
                        return(null);                        // The key was already checked
                    }

                    batchSize = entityBatch.Length;
                }

                if (entityBatch == null)
                {
                    entityBatch = await(source.PersistenceContext.BatchFetchQueue.GetEntityBatchAsync(persister, @event.EntityId, batchSize, false, cancellationToken)).ConfigureAwait(false);
                }

                // Ignore null values as the retrieved batch may contains them when there are not enough
                // uninitialized entities in the queue
                var keys = new List <CacheKey>(batchSize);
                for (var i = 0; i < entityBatch.Length; i++)
                {
                    var key = entityBatch[i];
                    if (key == null)
                    {
                        break;
                    }
                    keys.Add(source.GenerateCacheKey(key, persister.IdentifierType, persister.RootEntityName));
                }
                var cachedObjects = await(persister.Cache.GetManyAsync(keys.ToArray(), source.Timestamp, cancellationToken)).ConfigureAwait(false);
                for (var i = 1; i < cachedObjects.Length; i++)
                {
                    cancellationToken.ThrowIfCancellationRequested();
                    await(AssembleAsync(
                              keys[i],
                              cachedObjects[i],
                              new LoadEvent(entityBatch[i], @event.EntityClassName, @event.LockMode, @event.Session),
                              false)).ConfigureAwait(false);
                }
                cancellationToken.ThrowIfCancellationRequested();
                return(await(AssembleAsync(keys[0], cachedObjects[0], @event, true)).ConfigureAwait(false));
            }
            var cacheKey     = source.GenerateCacheKey(@event.EntityId, persister.IdentifierType, persister.RootEntityName);
            var cachedObject = await(persister.Cache.GetAsync(cacheKey, source.Timestamp, cancellationToken)).ConfigureAwait(false);

            cancellationToken.ThrowIfCancellationRequested();
            return(await(AssembleAsync(cacheKey, cachedObject, @event, true)).ConfigureAwait(false));

            Task <object> AssembleAsync(CacheKey ck, object ce, LoadEvent evt, bool alterStatistics)
            {
                try
                {
                    if (factory.Statistics.IsStatisticsEnabled && alterStatistics)
                    {
                        if (ce == null)
                        {
                            factory.StatisticsImplementor.SecondLevelCacheMiss(persister.Cache.RegionName);
                            log.Debug("Entity cache miss: {0}", ck);
                        }
                        else
                        {
                            factory.StatisticsImplementor.SecondLevelCacheHit(persister.Cache.RegionName);
                            log.Debug("Entity cache hit: {0}", ck);
                        }
                    }

                    if (ce != null)
                    {
                        CacheEntry entry = (CacheEntry)persister.CacheEntryStructure.Destructure(ce, factory);

                        // Entity was found in second-level cache...
                        // NH: Different behavior (take a look to options.ExactPersister (NH-295))
                        if (!options.ExactPersister || persister.EntityMetamodel.SubclassEntityNames.Contains(entry.Subclass))
                        {
                            return(AssembleCacheEntryAsync(entry, evt.EntityId, persister, evt, cancellationToken));
                        }
                    }

                    return(Task.FromResult <object>(null));
                }
                catch (Exception ex)
                {
                    return(Task.FromException <object>(ex));
                }
            }
        }
Example #2
0
 private bool ShouldExecuteBatch(IEntityPersister persister, AbstractCacheBatch batch)
 {
     return(batch != _currentBatch || _currentPersister != persister ||
            _currentBatch.BatchSize >= persister.GetBatchSize());
 }
Example #3
0
        /// <summary> Attempts to load the entity from the second-level cache. </summary>
        /// <param name="event">The load event </param>
        /// <param name="persister">The persister for the entity being requested for load </param>
        /// <param name="options">The load options. </param>
        /// <returns> The entity from the second-level cache, or null. </returns>
        protected virtual object LoadFromSecondLevelCache(LoadEvent @event, IEntityPersister persister, LoadType options)
        {
            ISessionImplementor source = @event.Session;
            bool useCache = persister.HasCache && source.CacheMode.HasFlag(CacheMode.Get) &&
                            @event.LockMode.LessThan(LockMode.Read);

            if (!useCache)
            {
                return(null);
            }
            ISessionFactoryImplementor factory = source.Factory;
            var batchSize = persister.GetBatchSize();

            if (batchSize > 1 && persister.Cache.PreferMultipleGet())
            {
                // The first item in the array is the item that we want to load
                var entityBatch =
                    source.PersistenceContext.BatchFetchQueue.GetEntityBatch(persister, @event.EntityId, batchSize, false);
                // Ignore null values as the retrieved batch may contains them when there are not enough
                // uninitialized entities in the queue
                var keys = new List <CacheKey>(batchSize);
                for (var i = 0; i < entityBatch.Length; i++)
                {
                    var key = entityBatch[i];
                    if (key == null)
                    {
                        break;
                    }
                    keys.Add(source.GenerateCacheKey(key, persister.IdentifierType, persister.RootEntityName));
                }
                var cachedObjects = persister.Cache.GetMany(keys.ToArray(), source.Timestamp);
                for (var i = 1; i < cachedObjects.Length; i++)
                {
                    Assemble(
                        keys[i],
                        cachedObjects[i],
                        new LoadEvent(entityBatch[i], @event.EntityClassName, @event.LockMode, @event.Session),
                        false);
                }
                return(Assemble(keys[0], cachedObjects[0], @event, true));
            }
            var cacheKey     = source.GenerateCacheKey(@event.EntityId, persister.IdentifierType, persister.RootEntityName);
            var cachedObject = persister.Cache.Get(cacheKey, source.Timestamp);

            return(Assemble(cacheKey, cachedObject, @event, true));

            object Assemble(CacheKey ck, object ce, LoadEvent evt, bool alterStatistics)
            {
                if (factory.Statistics.IsStatisticsEnabled && alterStatistics)
                {
                    if (ce == null)
                    {
                        factory.StatisticsImplementor.SecondLevelCacheMiss(persister.Cache.RegionName);
                        log.Debug("Entity cache miss: {0}", ck);
                    }
                    else
                    {
                        factory.StatisticsImplementor.SecondLevelCacheHit(persister.Cache.RegionName);
                        log.Debug("Entity cache hit: {0}", ck);
                    }
                }

                if (ce != null)
                {
                    CacheEntry entry = (CacheEntry)persister.CacheEntryStructure.Destructure(ce, factory);

                    // Entity was found in second-level cache...
                    // NH: Different behavior (take a look to options.ExactPersister (NH-295))
                    if (!options.ExactPersister || persister.EntityMetamodel.SubclassEntityNames.Contains(entry.Subclass))
                    {
                        return(AssembleCacheEntry(entry, evt.EntityId, persister, evt));
                    }
                }

                return(null);
            }
        }