Skip to content

Commit 1fbf02d

Browse files
Merge branch 'v8/dev' into v8/contrib
2 parents e59f855 + 2aad208 commit 1fbf02d

File tree

4 files changed

+133
-43
lines changed

4 files changed

+133
-43
lines changed

src/SolutionInfo.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,5 @@
1818
[assembly: AssemblyVersion("8.0.0")]
1919

2020
// these are FYI and changed automatically
21-
[assembly: AssemblyFileVersion("8.17.0")]
22-
[assembly: AssemblyInformationalVersion("8.17.0")]
21+
[assembly: AssemblyFileVersion("8.17.1")]
22+
[assembly: AssemblyInformationalVersion("8.17.1")]

src/Umbraco.Tests/Cache/DistributedCacheBinderTests.cs

Lines changed: 67 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Collections.Generic;
23
using System.Linq;
34
using System.Threading;
45
using Moq;
@@ -10,6 +11,7 @@
1011
using Umbraco.Core.Models.Membership;
1112
using Umbraco.Core.Services;
1213
using Umbraco.Core.Services.Changes;
14+
using Umbraco.Tests.TestHelpers.Entities;
1315
using Umbraco.Tests.Testing;
1416
using Umbraco.Tests.Testing.Objects.Accessors;
1517
using Umbraco.Web;
@@ -168,17 +170,73 @@ public void CanHandleEvent()
168170
}
169171

170172
[Test]
171-
public void OnlyHandlesOnContentTypeEvent()
173+
public void GroupsContentTypeEvents()
172174
{
173-
var definitions = new IEventDefinition[]
175+
var num = 30;
176+
var contentTypes = Enumerable.Repeat(MockedContentTypes.CreateBasicContentType(), num);
177+
var mediaTypes = Enumerable.Repeat(MockedContentTypes.CreateImageMediaType(), num);
178+
var memberTypes = Enumerable.Repeat(MockedContentTypes.CreateSimpleMemberType(), num);
179+
var definitionsContent = contentTypes.SelectMany(x => new IEventDefinition[]
174180
{
175-
new EventDefinition<IContentTypeService, ContentTypeChange<IContentType>.EventArgs>(null, Current.Services.ContentTypeService, new ContentTypeChange<IContentType>.EventArgs(Enumerable.Empty<ContentTypeChange<IContentType>>()), "Changed"),
176-
new EventDefinition<IContentTypeService, SaveEventArgs<IContentType>>(null, Current.Services.ContentTypeService, new SaveEventArgs<IContentType>(Enumerable.Empty<IContentType>()), "Saved"),
177-
new EventDefinition<IContentTypeService, ContentTypeChange<IContentType>.EventArgs>(null, Current.Services.ContentTypeService, new ContentTypeChange<IContentType>.EventArgs(Enumerable.Empty<ContentTypeChange<IContentType>>()), "Changed"),
178-
new EventDefinition<IContentTypeService, SaveEventArgs<IContentType>>(null, Current.Services.ContentTypeService, new SaveEventArgs<IContentType>(Enumerable.Empty<IContentType>()), "Saved"),
179-
};
180-
var result = DistributedCacheBinder.GetReducedEventList(definitions);
181-
Assert.AreEqual(1, result.Count());
181+
new EventDefinition<IContentTypeService, ContentTypeChange<IContentType>.EventArgs>(null, Current.Services.ContentTypeService, new ContentTypeChange<IContentType>.EventArgs(new ContentTypeChange<IContentType>(x, ContentTypeChangeTypes.Create)), "Changed"),
182+
new EventDefinition<IContentTypeService, SaveEventArgs<IContentType>>(null, Current.Services.ContentTypeService, new SaveEventArgs<IContentType>(x), "Saved"),
183+
});
184+
185+
var definitionsMedia = mediaTypes.SelectMany(x => new IEventDefinition[]
186+
{
187+
new EventDefinition<IMediaTypeService, ContentTypeChange<IMediaType>.EventArgs>(null, Current.Services.MediaTypeService, new ContentTypeChange<IMediaType>.EventArgs(new ContentTypeChange<IMediaType>(x, ContentTypeChangeTypes.Create)), "Changed"),
188+
new EventDefinition<IMediaTypeService, SaveEventArgs<IMediaType>>(null, Current.Services.MediaTypeService, new SaveEventArgs<IMediaType>(x), "Saved"),
189+
});
190+
var definitionsMember = memberTypes.SelectMany(x => new IEventDefinition[]
191+
{
192+
new EventDefinition<IMemberTypeService, ContentTypeChange<IMemberType>.EventArgs>(null, Current.Services.MemberTypeService, new ContentTypeChange<IMemberType>.EventArgs(new ContentTypeChange<IMemberType>(x, ContentTypeChangeTypes.Create)), "Changed"),
193+
new EventDefinition<IMemberTypeService, SaveEventArgs<IMemberType>>(null, Current.Services.MemberTypeService, new SaveEventArgs<IMemberType>(x), "Saved"),
194+
});
195+
196+
var definitions = new List<IEventDefinition>();
197+
definitions.AddRange(definitionsContent);
198+
definitions.AddRange(definitionsMedia);
199+
definitions.AddRange(definitionsMember);
200+
201+
var result = DistributedCacheBinder.GetGroupedEventList(definitions);
202+
203+
Assert.Multiple(() =>
204+
{
205+
Assert.AreEqual(num * 6, definitions.Count(), "Precondition is we have many definitions");
206+
Assert.AreEqual(6, result.Count(), "Unexpected number of reduced definitions");
207+
foreach (var eventDefinition in result)
208+
{
209+
if (eventDefinition.Args is SaveEventArgs<IContentType> saveContentEventArgs)
210+
{
211+
Assert.AreEqual(num, saveContentEventArgs.SavedEntities.Count());
212+
}
213+
214+
if (eventDefinition.Args is ContentTypeChange<IContentType>.EventArgs changeContentEventArgs)
215+
{
216+
Assert.AreEqual(num, changeContentEventArgs.Changes.Count());
217+
}
218+
219+
if (eventDefinition.Args is SaveEventArgs<IMediaType> saveMediaEventArgs)
220+
{
221+
Assert.AreEqual(num, saveMediaEventArgs.SavedEntities.Count());
222+
}
223+
224+
if (eventDefinition.Args is ContentTypeChange<IMediaType>.EventArgs changeMediaEventArgs)
225+
{
226+
Assert.AreEqual(num, changeMediaEventArgs.Changes.Count());
227+
}
228+
229+
if (eventDefinition.Args is SaveEventArgs<IMemberType> saveMemberEventArgs)
230+
{
231+
Assert.AreEqual(num, saveMemberEventArgs.SavedEntities.Count());
232+
}
233+
234+
if (eventDefinition.Args is ContentTypeChange<IMemberType>.EventArgs changeMemberEventArgs)
235+
{
236+
Assert.AreEqual(num, changeMemberEventArgs.Changes.Count());
237+
}
238+
}
239+
});
182240
}
183241
}
184242
}

src/Umbraco.Web.UI/Umbraco.Web.UI.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -348,9 +348,9 @@
348348
<WebProjectProperties>
349349
<UseIIS>False</UseIIS>
350350
<AutoAssignPort>True</AutoAssignPort>
351-
<DevelopmentServerPort>8170</DevelopmentServerPort>
351+
<DevelopmentServerPort>8171</DevelopmentServerPort>
352352
<DevelopmentServerVPath>/</DevelopmentServerVPath>
353-
<IISUrl>http://localhost:8170</IISUrl>
353+
<IISUrl>http://localhost:8171</IISUrl>
354354
<NTLMAuthentication>False</NTLMAuthentication>
355355
<UseCustomServer>False</UseCustomServer>
356356
<CustomServerUrl>

src/Umbraco.Web/Cache/DistributedCacheBinder.cs

Lines changed: 62 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
using Umbraco.Core;
77
using Umbraco.Core.Events;
88
using Umbraco.Core.Logging;
9+
using Umbraco.Core.Models;
10+
using Umbraco.Core.Services;
11+
using Umbraco.Core.Services.Changes;
912

1013
namespace Umbraco.Web.Cache
1114
{
@@ -66,10 +69,9 @@ public void HandleEvents(IEnumerable<IEventDefinition> events)
6669
using (_umbracoContextFactory.EnsureUmbracoContext())
6770
{
6871
// When it comes to content types types, a change to any single one will trigger a reload of the content and media caches.
69-
// As far as I (AB) can tell, there's no type specific logic here, they all clear caches for all content types, and trigger a reload of all content and media.
70-
// We also have events registered for Changed and Saved, which do the same thing, so really only need one of these.
71-
// Hence if we have more than one document or media types, we can and should only handle one of the events for one, to avoid repeated cache reloads.
72-
foreach (var e in GetReducedEventList(events))
72+
// We can reduce the impact of that by grouping the events to invoke just one per type, providing a collection of the individual arguments.
73+
var groupedEvents = GetGroupedEventList(events);
74+
foreach (var e in groupedEvents)
7375
{
7476
var handler = FindHandler(e);
7577
if (handler == null)
@@ -86,47 +88,77 @@ public void HandleEvents(IEnumerable<IEventDefinition> events)
8688
}
8789

8890
// Internal for tests
89-
internal static IEnumerable<IEventDefinition> GetReducedEventList(IEnumerable<IEventDefinition> events)
91+
internal static IEnumerable<IEventDefinition> GetGroupedEventList(IEnumerable<IEventDefinition> events)
9092
{
91-
var reducedEvents = new List<IEventDefinition>();
93+
var groupedEvents = new List<IEventDefinition>();
9294

93-
var gotDoumentType = false;
94-
var gotMediaType = false;
95-
var gotMemberType = false;
95+
var grouped = events.GroupBy(x => x.GetType());
9696

97-
foreach (var evt in events)
97+
foreach (var group in grouped)
9898
{
99-
if (evt.Sender.ToString().Contains(nameof(Core.Services.Implement.ContentTypeService)))
99+
if (group.Key == typeof(EventDefinition<IContentTypeService, SaveEventArgs<IContentType>>))
100100
{
101-
if (gotDoumentType == false)
102-
{
103-
reducedEvents.Add(evt);
104-
gotDoumentType = true;
105-
}
101+
GroupSaveEvents<IContentTypeService, IContentType>(groupedEvents, group);
106102
}
107-
else if (evt.Sender.ToString().Contains(nameof(Core.Services.Implement.MediaTypeService)))
103+
else if (group.Key == typeof(EventDefinition<IContentTypeService, ContentTypeChange<IContentType>.EventArgs>))
108104
{
109-
if (gotMediaType == false)
110-
{
111-
reducedEvents.Add(evt);
112-
gotMediaType = true;
113-
}
105+
GroupChangeEvents<IContentTypeService, IContentType>(groupedEvents, group);
114106
}
115-
else if (evt.Sender.ToString().Contains(nameof(Core.Services.Implement.MemberTypeService)))
107+
else if (group.Key == typeof(EventDefinition<IMediaTypeService, SaveEventArgs<IMediaType>>))
116108
{
117-
if (gotMemberType == false)
118-
{
119-
reducedEvents.Add(evt);
120-
gotMemberType = true;
121-
}
109+
GroupSaveEvents<IMediaTypeService, IMediaType>(groupedEvents, group);
110+
}
111+
else if (group.Key == typeof(EventDefinition<IMediaTypeService, ContentTypeChange<IMediaType>.EventArgs>))
112+
{
113+
GroupChangeEvents<IMediaTypeService, IMediaType>(groupedEvents, group);
114+
}
115+
else if (group.Key == typeof(EventDefinition<IMemberTypeService, SaveEventArgs<IMemberType>>))
116+
{
117+
GroupSaveEvents<IMemberTypeService, IMemberType>(groupedEvents, group);
118+
}
119+
else if (group.Key == typeof(EventDefinition<IMemberTypeService, ContentTypeChange<IMemberType>.EventArgs>))
120+
{
121+
GroupChangeEvents<IMemberTypeService, IMemberType>(groupedEvents, group);
122122
}
123123
else
124124
{
125-
reducedEvents.Add(evt);
125+
groupedEvents.AddRange(group);
126126
}
127127
}
128128

129-
return reducedEvents;
129+
return groupedEvents;
130+
}
131+
132+
private static void GroupSaveEvents<TService, TType>(List<IEventDefinition> groupedEvents, IGrouping<Type, IEventDefinition> group)
133+
where TService : IContentTypeBaseService
134+
where TType : IContentTypeBase
135+
{
136+
var groupedGroups = group.GroupBy(x => (x.EventName, x.Sender));
137+
138+
foreach (var groupedGroup in groupedGroups)
139+
{
140+
groupedEvents.Add(new EventDefinition<TService, SaveEventArgs<TType>>(
141+
null,
142+
(TService)groupedGroup.Key.Sender,
143+
new SaveEventArgs<TType>(groupedGroup.SelectMany(x => ((SaveEventArgs<TType>)x.Args).SavedEntities)),
144+
groupedGroup.Key.EventName));
145+
}
146+
}
147+
148+
private static void GroupChangeEvents<TService, TType>(List<IEventDefinition> groupedEvents, IGrouping<Type, IEventDefinition> group)
149+
where TService : IContentTypeBaseService
150+
where TType : class, IContentTypeComposition
151+
{
152+
var groupedGroups = group.GroupBy(x => (x.EventName, x.Sender));
153+
154+
foreach (var groupedGroup in groupedGroups)
155+
{
156+
groupedEvents.Add(new EventDefinition<TService, ContentTypeChange<TType>.EventArgs>(
157+
null,
158+
(TService)groupedGroup.Key.Sender,
159+
new ContentTypeChange<TType>.EventArgs(groupedGroup.SelectMany(x => ((ContentTypeChange<TType>.EventArgs)x.Args).Changes)),
160+
groupedGroup.Key.EventName));
161+
}
130162
}
131163
}
132164
}

0 commit comments

Comments
 (0)