/// <summary>
        /// Finish the process of collection-loading for this bound result set. Mainly this
        /// involves cleaning up resources and notifying the collections that loading is
        /// complete.
        /// </summary>
        /// <param name="persister">The persister for which to complete loading.</param>
        /// <param name="skipCache">Indicates if collection must not be put in cache.</param>
        /// <param name="cacheBatcher">The cache batcher used to batch put the collections into the cache.</param>
        /// <param name="cancellationToken">A cancellation token that can be used to cancel the work</param>
        public async Task EndLoadingCollectionsAsync(ICollectionPersister persister, bool skipCache, CacheBatcher cacheBatcher, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();
            if (!loadContexts.HasLoadingCollectionEntries && (localLoadingCollectionKeys.Count == 0))
            {
                return;
            }

            // in an effort to avoid concurrent-modification-exceptions (from
            // potential recursive calls back through here as a result of the
            // eventual call to PersistentCollection#endRead), we scan the
            // internal loadingCollections map for matches and store those matches
            // in a temp collection.  the temp collection is then used to "drive"
            // the #endRead processing.
            List <CollectionKey>          toRemove = new List <CollectionKey>();
            List <LoadingCollectionEntry> matches  = new List <LoadingCollectionEntry>();

            foreach (CollectionKey collectionKey in localLoadingCollectionKeys)
            {
                ISessionImplementor session = LoadContext.PersistenceContext.Session;

                LoadingCollectionEntry lce = loadContexts.LocateLoadingCollectionEntry(collectionKey);
                if (lce == null)
                {
                    log.Warn("In CollectionLoadContext#endLoadingCollections, localLoadingCollectionKeys contained [{0}], but no LoadingCollectionEntry was found in loadContexts",
                             collectionKey);
                }
                else if (lce.ResultSet == resultSet && lce.Persister == persister)
                {
                    matches.Add(lce);
                    if (lce.Collection.Owner == null)
                    {
                        session.PersistenceContext.AddUnownedCollection(new CollectionKey(persister, lce.Key),
                                                                        lce.Collection);
                    }
                    if (log.IsDebugEnabled())
                    {
                        log.Debug("removing collection load entry [{0}]", lce);
                    }

                    // todo : i'd much rather have this done from #endLoadingCollection(CollectionPersister,LoadingCollectionEntry)...
                    loadContexts.UnregisterLoadingCollectionXRef(collectionKey);
                    toRemove.Add(collectionKey);
                }
            }
            localLoadingCollectionKeys.ExceptWith(toRemove);

            await(EndLoadingCollectionsAsync(persister, matches, skipCache, cacheBatcher, cancellationToken)).ConfigureAwait(false);
            if ((localLoadingCollectionKeys.Count == 0))
            {
                // todo : hack!!!
                // NOTE : here we cleanup the load context when we have no more local
                // LCE entries.  This "works" for the time being because really
                // only the collection load contexts are implemented.  Long term,
                // this cleanup should become part of the "close result set"
                // processing from the (sandbox/jdbc) jdbc-container code.
                loadContexts.Cleanup(resultSet);
            }
        }
示例#2
0
        /// <summary>
        /// Register a loading collection xref.
        /// </summary>
        /// <param name="entryKey">The xref collection key </param>
        /// <param name="entry">The corresponding loading collection entry </param>
        /// <remarks>
        /// This xref map is used because sometimes a collection is in process of
        /// being loaded from one result set, but needs to be accessed from the
        /// context of another "nested" result set processing.
        /// Implementation note: package protected, as this is meant solely for use
        /// by {@link CollectionLoadContext} to be able to locate collections
        /// being loaded by other {@link CollectionLoadContext}s/{@link ResultSet}s.
        /// </remarks>
        internal void RegisterLoadingCollectionXRef(CollectionKey entryKey, LoadingCollectionEntry entry)
        {
            if (xrefLoadingCollectionEntries == null)
            {
                xrefLoadingCollectionEntries = new Dictionary <CollectionKey, LoadingCollectionEntry>();
            }

            xrefLoadingCollectionEntries[entryKey] = entry;
        }
示例#3
0
        private async Task EndLoadingCollectionAsync(LoadingCollectionEntry lce, ICollectionPersister persister,
                                                     Action <CachePutData> cacheBatchingHandler, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();
            if (log.IsDebugEnabled())
            {
                log.Debug("ending loading collection [{0}]", lce);
            }

            var persistenceContext = LoadContext.PersistenceContext;
            var session            = persistenceContext.Session;

            bool statsEnabled = session.Factory.Statistics.IsStatisticsEnabled;
            var  stopWath     = new Stopwatch();

            if (statsEnabled)
            {
                stopWath.Start();
            }

            bool hasNoQueuedAdds = lce.Collection.EndRead(persister);             // warning: can cause a recursive calls! (proxy initialization)

            if (persister.CollectionType.HasHolder())
            {
                persistenceContext.AddCollectionHolder(lce.Collection);
            }

            CollectionEntry ce = persistenceContext.GetCollectionEntry(lce.Collection);

            if (ce == null)
            {
                ce = persistenceContext.AddInitializedCollection(persister, lce.Collection, lce.Key);
            }
            else
            {
                ce.PostInitialize(lce.Collection, persistenceContext);
            }

            bool addToCache = hasNoQueuedAdds && persister.HasCache &&
                              session.CacheMode.HasFlag(CacheMode.Put) && !ce.IsDoremove;   // and this is not a forced initialization during flush

            if (addToCache)
            {
                await(AddCollectionToCacheAsync(lce, persister, cacheBatchingHandler, cancellationToken)).ConfigureAwait(false);
            }

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

            if (statsEnabled)
            {
                stopWath.Stop();
                session.Factory.StatisticsImplementor.LoadCollection(persister.Role, stopWath.Elapsed);
            }
        }
示例#4
0
        private void EndLoadingCollection(LoadingCollectionEntry lce, ICollectionPersister persister)
        {
            if (log.IsDebugEnabled)
            {
                log.Debug("ending loading collection [" + lce + "]");
            }
            ISessionImplementor session = LoadContext.PersistenceContext.Session;
            EntityMode          em      = session.EntityMode;

            bool statsEnabled = session.Factory.Statistics.IsStatisticsEnabled;
            var  stopWath     = new Stopwatch();

            if (statsEnabled)
            {
                stopWath.Start();
            }

            bool hasNoQueuedAdds = lce.Collection.EndRead(persister);             // warning: can cause a recursive calls! (proxy initialization)

            if (persister.CollectionType.HasHolder(em))
            {
                LoadContext.PersistenceContext.AddCollectionHolder(lce.Collection);
            }

            CollectionEntry ce = LoadContext.PersistenceContext.GetCollectionEntry(lce.Collection);

            if (ce == null)
            {
                ce = LoadContext.PersistenceContext.AddInitializedCollection(persister, lce.Collection, lce.Key);
            }
            else
            {
                ce.PostInitialize(lce.Collection);
            }

            bool addToCache = hasNoQueuedAdds && persister.HasCache &&
                              ((session.CacheMode & CacheMode.Put) == CacheMode.Put) && !ce.IsDoremove;   // and this is not a forced initialization during flush

            if (addToCache)
            {
                AddCollectionToCache(lce, persister);
            }

            if (log.IsDebugEnabled)
            {
                log.Debug("collection fully initialized: " + MessageHelper.InfoString(persister, lce.Key, session.Factory));
            }

            if (statsEnabled)
            {
                stopWath.Stop();
                session.Factory.StatisticsImplementor.LoadCollection(persister.Role, stopWath.Elapsed);
            }
        }
        /// <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);
            }
        }
示例#6
0
        /// <summary>
        /// Attempt to locate the loading collection given the owner's key.  The lookup here
        /// occurs against all result-set contexts...
        /// </summary>
        /// <param name="persister">The collection persister </param>
        /// <param name="ownerKey">The owner key </param>
        /// <returns> The loading collection, or null if not found. </returns>
        public IPersistentCollection LocateLoadingCollection(ICollectionPersister persister, object ownerKey)
        {
            LoadingCollectionEntry lce = LocateLoadingCollectionEntry(new CollectionKey(persister, ownerKey));

            if (lce != null)
            {
                if (log.IsDebugEnabled())
                {
                    log.Debug("returning loading collection:{0}", MessageHelper.CollectionInfoString(persister, ownerKey, Session.Factory));
                }
                return(lce.Collection);
            }
            else
            {
                return(null);
            }
        }
示例#7
0
        /// <summary>
        /// Attempt to locate the loading collection given the owner's key.  The lookup here
        /// occurs against all result-set contexts...
        /// </summary>
        /// <param name="persister">The collection persister </param>
        /// <param name="ownerKey">The owner key </param>
        /// <returns> The loading collection, or null if not found. </returns>
        public IPersistentCollection LocateLoadingCollection(ICollectionPersister persister, object ownerKey)
        {
            LoadingCollectionEntry lce = LocateLoadingCollectionEntry(new CollectionKey(persister, ownerKey, Session.EntityMode));

            if (lce != null)
            {
                if (log.IsDebugEnabled)
                {
                    log.Debug("returning loading collection:" + MessageHelper.InfoString(persister, ownerKey, Session.Factory));
                }
                return(lce.Collection);
            }
            else
            {
                // todo : should really move this log statement to CollectionType, where this is used from...
                if (log.IsDebugEnabled)
                {
                    log.Debug("creating collection wrapper:" + MessageHelper.InfoString(persister, ownerKey, Session.Factory));
                }
                return(null);
            }
        }
		/// <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>
		private void AddCollectionToCache(LoadingCollectionEntry lce, ICollectionPersister persister)
		{
			ISessionImplementor session = LoadContext.PersistenceContext.Session;
			ISessionFactoryImplementor factory = session.Factory;

			if (log.IsDebugEnabled)
			{
				log.Debug("Caching collection: " + MessageHelper.InfoString(persister, lce.Key, factory));
			}

			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);
				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 = persister.Cache.Put(cacheKey, persister.CacheEntryStructure.Structure(entry), 
			                    session.Timestamp, version, versionComparator,
													factory.Settings.IsMinimalPutsEnabled && session.CacheMode != CacheMode.Refresh);

			if (put && factory.Statistics.IsStatisticsEnabled)
			{
				factory.StatisticsImplementor.SecondLevelCachePut(persister.Cache.RegionName);
			}
		}
		private void EndLoadingCollection(LoadingCollectionEntry lce, ICollectionPersister persister)
		{
			if (log.IsDebugEnabled)
			{
				log.Debug("ending loading collection [" + lce + "]");
			}
			ISessionImplementor session = LoadContext.PersistenceContext.Session;
			EntityMode em = session.EntityMode;

			bool statsEnabled = session.Factory.Statistics.IsStatisticsEnabled;
			var stopWath = new Stopwatch();
			if (statsEnabled)
			{
				stopWath.Start();
			}

			bool hasNoQueuedAdds = lce.Collection.EndRead(persister); // warning: can cause a recursive calls! (proxy initialization)

			if (persister.CollectionType.HasHolder(em))
			{
				LoadContext.PersistenceContext.AddCollectionHolder(lce.Collection);
			}

			CollectionEntry ce = LoadContext.PersistenceContext.GetCollectionEntry(lce.Collection);
			if (ce == null)
			{
				ce = LoadContext.PersistenceContext.AddInitializedCollection(persister, lce.Collection, lce.Key);
			}
			else
			{
				ce.PostInitialize(lce.Collection);
			}

			bool addToCache = hasNoQueuedAdds && persister.HasCache && 
				((session.CacheMode & CacheMode.Put) == CacheMode.Put) && !ce.IsDoremove; // and this is not a forced initialization during flush

			if (addToCache)
			{
				AddCollectionToCache(lce, persister);
			}

			if (log.IsDebugEnabled)
			{
				log.Debug("collection fully initialized: " + MessageHelper.InfoString(persister, lce.Key, session.Factory));
			}

			if (statsEnabled)
			{
				stopWath.Stop();
				session.Factory.StatisticsImplementor.LoadCollection(persister.Role, stopWath.Elapsed);
			}
		}
        /// <summary>
        /// Retrieve the collection that is being loaded as part of processing this result set.
        /// </summary>
        /// <param name="persister">The persister for the collection being requested. </param>
        /// <param name="key">The key of the collection being requested. </param>
        /// <returns> The loading collection (see discussion above). </returns>
        /// <remarks>
        /// Basically, there are two valid return values from this method:<ul>
        /// <li>an instance of {@link PersistentCollection} which indicates to
        /// continue loading the result set row data into that returned collection
        /// instance; this may be either an instance already associated and in the
        /// midst of being loaded, or a newly instantiated instance as a matching
        /// associated collection was not found.</li>
        /// <li><i>null</i> indicates to ignore the corresponding result set row
        /// data relating to the requested collection; this indicates that either
        /// the collection was found to already be associated with the persistence
        /// context in a fully loaded state, or it was found in a loading state
        /// associated with another result set processing context.</li>
        /// </ul>
        /// </remarks>
        public IPersistentCollection GetLoadingCollection(ICollectionPersister persister, object key)
        {
            CollectionKey collectionKey = new CollectionKey(persister, key);

            if (log.IsDebugEnabled())
            {
                log.Debug("starting attempt to find loading collection [{0}]", MessageHelper.InfoString(persister.Role, key));
            }
            LoadingCollectionEntry loadingCollectionEntry = loadContexts.LocateLoadingCollectionEntry(collectionKey);

            if (loadingCollectionEntry == null)
            {
                // look for existing collection as part of the persistence context
                IPersistentCollection collection = loadContexts.PersistenceContext.GetCollection(collectionKey);
                if (collection != null)
                {
                    if (collection.WasInitialized)
                    {
                        log.Debug("collection already initialized; ignoring");
                        return(null);                        // ignore this row of results! Note the early exit
                    }
                    else
                    {
                        // initialize this collection
                        log.Debug("collection not yet initialized; initializing");
                    }
                }
                else
                {
                    object owner            = loadContexts.PersistenceContext.GetCollectionOwner(key, persister);
                    bool   newlySavedEntity = owner != null && loadContexts.PersistenceContext.GetEntry(owner).Status != Status.Loading;
                    if (newlySavedEntity)
                    {
                        // important, to account for newly saved entities in query
                        // todo : some kind of check for new status...
                        log.Debug("owning entity already loaded; ignoring");
                        return(null);
                    }
                    else
                    {
                        // create one
                        if (log.IsDebugEnabled())
                        {
                            // Do not log the resultSet as-is, it is an IEnumerable which may get enumerated by loggers.
                            // (Serilog does that.) See #1667.
                            log.Debug("instantiating new collection [key={0}, rs={1}]", key, resultSet.GetType());
                        }
                        collection = persister.CollectionType.Instantiate(loadContexts.PersistenceContext.Session, persister, key);
                    }
                }
                collection.BeforeInitialize(persister, -1);
                collection.BeginRead();
                localLoadingCollectionKeys.Add(collectionKey);
                loadContexts.RegisterLoadingCollectionXRef(collectionKey, new LoadingCollectionEntry(resultSet, persister, key, collection));
                return(collection);
            }
            else
            {
                if (loadingCollectionEntry.ResultSet == resultSet)
                {
                    log.Debug("found loading collection bound to current result set processing; reading row");
                    return(loadingCollectionEntry.Collection);
                }
                else
                {
                    // ignore this row, the collection is in process of
                    // being loaded somewhere further "up" the stack
                    log.Debug("collection is already being initialized; ignoring row");
                    return(null);
                }
            }
        }
        private void EndLoadingCollection(
            LoadingCollectionEntry lce,
            ICollectionPersister persister,
            Action <CachePutData> cacheBatchingHandler,
            bool skipCache)
        {
            if (log.IsDebugEnabled())
            {
                log.Debug("ending loading collection [{0}]", lce);
            }

            var persistenceContext = LoadContext.PersistenceContext;
            var session            = persistenceContext.Session;

            Stopwatch stopWatch = null;

            if (session.Factory.Statistics.IsStatisticsEnabled)
            {
                stopWatch = Stopwatch.StartNew();
            }

            bool hasNoQueuedOperations = lce.Collection.EndRead(persister);             // warning: can cause a recursive calls! (proxy initialization)

            if (persister.CollectionType.HasHolder())
            {
                persistenceContext.AddCollectionHolder(lce.Collection);
            }

            CollectionEntry ce = persistenceContext.GetCollectionEntry(lce.Collection);

            if (ce == null)
            {
                ce = persistenceContext.AddInitializedCollection(persister, lce.Collection, lce.Key);
            }
            else
            {
                ce.PostInitialize(lce.Collection, persistenceContext);
            }

            bool addToCache = hasNoQueuedOperations && !skipCache && persister.HasCache &&
                              session.CacheMode.HasFlag(CacheMode.Put) &&
                              // and this is not a forced initialization during flush
                              !ce.IsDoremove;

            if (addToCache)
            {
                AddCollectionToCache(lce, persister, cacheBatchingHandler);
            }

            if (!hasNoQueuedOperations)
            {
                lce.Collection.ApplyQueuedOperations();
            }

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

            if (stopWatch != null)
            {
                stopWatch.Stop();
                session.Factory.StatisticsImplementor.LoadCollection(persister.Role, stopWatch.Elapsed);
            }
        }
示例#12
0
		/// <summary> 
		/// Register a loading collection xref. 
		/// </summary>
		/// <param name="entryKey">The xref collection key </param>
		/// <param name="entry">The corresponding loading collection entry </param>
		/// <remarks>
		/// This xref map is used because sometimes a collection is in process of
		/// being loaded from one result set, but needs to be accessed from the
		/// context of another "nested" result set processing.
		/// Implementation note: package protected, as this is meant solely for use
		/// by {@link CollectionLoadContext} to be able to locate collections
		/// being loaded by other {@link CollectionLoadContext}s/{@link ResultSet}s.
		/// </remarks>
		internal void RegisterLoadingCollectionXRef(CollectionKey entryKey, LoadingCollectionEntry entry)
		{
			if (xrefLoadingCollectionEntries == null)
				xrefLoadingCollectionEntries = new Dictionary<CollectionKey, LoadingCollectionEntry>();

			xrefLoadingCollectionEntries[entryKey] = entry;
		}