/// <summary>
        /// Updates indexes based on content changes
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        public void Handle(ContentCacheRefresherNotification args)
        {
            if (!_umbracoIndexingHandler.Enabled)
            {
                return;
            }
            if (Suspendable.ExamineEvents.CanIndex == false)
            {
                return;
            }

            if (args.MessageType != MessageType.RefreshByPayload)
            {
                throw new NotSupportedException();
            }

            // Used to track permanent deletions so we can bulk delete from the index
            // when needed. For example, when emptying the recycle bin, else it will
            // individually update the index which will be much slower.
            HashSet <int> deleteBatch = null;

            foreach (var payload in (ContentCacheRefresher.JsonPayload[])args.MessageObject)
            {
                if (payload.ChangeTypes.HasType(TreeChangeTypes.Remove))
                {
                    if (deleteBatch == null)
                    {
                        deleteBatch = new HashSet <int>();
                    }

                    deleteBatch.Add(payload.Id);
                }
                else if (payload.ChangeTypes.HasType(TreeChangeTypes.RefreshAll))
                {
                    // ExamineEvents does not support RefreshAll
                    // just ignore that payload
                    // so what?!

                    // TODO: Rebuild the index at this point?
                }
                else // RefreshNode or RefreshBranch (maybe trashed)
                {
                    if (deleteBatch != null && deleteBatch.Contains(payload.Id))
                    {
                        // the same node has already been deleted, to ensure ordering is
                        // handled, we'll need to execute all queued deleted items now
                        // and reset the deleted items list.
                        _umbracoIndexingHandler.DeleteIndexForEntities(deleteBatch, false);
                        deleteBatch = null;
                    }

                    // don't try to be too clever - refresh entirely
                    // there has to be race conditions in there ;-(

                    var content = _contentService.GetById(payload.Id);
                    if (content == null)
                    {
                        // gone fishing, remove entirely from all indexes (with descendants)
                        _umbracoIndexingHandler.DeleteIndexForEntity(payload.Id, false);
                        continue;
                    }

                    IContent published = null;
                    if (content.Published && _contentService.IsPathPublished(content))
                    {
                        published = content;
                    }

                    if (published == null)
                    {
                        _umbracoIndexingHandler.DeleteIndexForEntity(payload.Id, true);
                    }

                    // just that content
                    _umbracoIndexingHandler.ReIndexForContent(content, published != null);

                    // branch
                    if (payload.ChangeTypes.HasType(TreeChangeTypes.RefreshBranch))
                    {
                        var       masked   = published == null ? null : new List <int>();
                        const int pageSize = 500;
                        var       page     = 0;
                        var       total    = long.MaxValue;
                        while (page * pageSize < total)
                        {
                            var descendants = _contentService.GetPagedDescendants(content.Id, page++, pageSize, out total,
                                                                                  //order by shallowest to deepest, this allows us to check it's published state without checking every item
                                                                                  ordering: Ordering.By("Path", Direction.Ascending));

                            foreach (var descendant in descendants)
                            {
                                published = null;
                                if (masked != null) // else everything is masked
                                {
                                    if (masked.Contains(descendant.ParentId) || !descendant.Published)
                                    {
                                        masked.Add(descendant.Id);
                                    }
                                    else
                                    {
                                        published = descendant;
                                    }
                                }

                                _umbracoIndexingHandler.ReIndexForContent(descendant, published != null);
                            }
                        }
                    }
                }

                // NOTE
                //
                // DeleteIndexForEntity is handled by UmbracoContentIndexer.DeleteFromIndex() which takes
                //  care of also deleting the descendants
                //
                // ReIndexForContent is NOT taking care of descendants so we have to reload everything
                //  again in order to process the branch - we COULD improve that by just reloading the
                //  XML from database instead of reloading content & re-serializing!
                //
                // BUT ... pretty sure it is! see test "Index_Delete_Index_Item_Ensure_Heirarchy_Removed"
            }

            if (deleteBatch != null)
            {
                // process the delete batch
                _umbracoIndexingHandler.DeleteIndexForEntities(deleteBatch, false);
            }
        }
예제 #2
0
        public void Handle(MediaCacheRefresherNotification args)
        {
            if (!_umbracoIndexingHandler.Enabled)
            {
                return;
            }

            if (Suspendable.ExamineEvents.CanIndex == false)
            {
                return;
            }

            if (args.MessageType != MessageType.RefreshByPayload)
            {
                throw new NotSupportedException();
            }

            // Used to track permanent deletions so we can bulk delete from the index
            // when needed. For example, when emptying the recycle bin, else it will
            // individually update the index which will be much slower.
            HashSet <int> deleteBatch = null;

            foreach (var payload in (MediaCacheRefresher.JsonPayload[])args.MessageObject)
            {
                if (payload.ChangeTypes.HasType(TreeChangeTypes.Remove))
                {
                    if (deleteBatch == null)
                    {
                        deleteBatch = new HashSet <int>();
                    }

                    deleteBatch.Add(payload.Id);
                }
                else if (payload.ChangeTypes.HasType(TreeChangeTypes.RefreshAll))
                {
                    // ExamineEvents does not support RefreshAll
                    // just ignore that payload
                    // so what?!
                }
                else // RefreshNode or RefreshBranch (maybe trashed)
                {
                    if (deleteBatch != null && deleteBatch.Contains(payload.Id))
                    {
                        // the same node has already been deleted, to ensure ordering is
                        // handled, we'll need to execute all queued deleted items now
                        // and reset the deleted items list.
                        _umbracoIndexingHandler.DeleteIndexForEntities(deleteBatch, false);
                        deleteBatch = null;
                    }

                    var media = _mediaService.GetById(payload.Id);
                    if (media == null)
                    {
                        // gone fishing, remove entirely
                        _umbracoIndexingHandler.DeleteIndexForEntity(payload.Id, false);
                        continue;
                    }

                    if (media.Trashed)
                    {
                        _umbracoIndexingHandler.DeleteIndexForEntity(payload.Id, true);
                    }

                    // just that media
                    _umbracoIndexingHandler.ReIndexForMedia(media, !media.Trashed);

                    // branch
                    if (payload.ChangeTypes.HasType(TreeChangeTypes.RefreshBranch))
                    {
                        const int pageSize = 500;
                        var       page     = 0;
                        var       total    = long.MaxValue;
                        while (page * pageSize < total)
                        {
                            var descendants = _mediaService.GetPagedDescendants(media.Id, page++, pageSize, out total);
                            foreach (var descendant in descendants)
                            {
                                _umbracoIndexingHandler.ReIndexForMedia(descendant, !descendant.Trashed);
                            }
                        }
                    }
                }
            }

            if (deleteBatch != null)
            {
                // process the delete batch
                _umbracoIndexingHandler.DeleteIndexForEntities(deleteBatch, false);
            }
        }