From d912bab9d2e08d835addcc3ae6d3f54b4735df5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Tue, 5 Nov 2024 10:08:31 +0100 Subject: [PATCH 1/5] update submodule --- src/Umbraco.Web.UI.Client | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client b/src/Umbraco.Web.UI.Client index 0065fc1143..a07923c2a6 160000 --- a/src/Umbraco.Web.UI.Client +++ b/src/Umbraco.Web.UI.Client @@ -1 +1 @@ -Subproject commit 0065fc11437a5cee384526d79021a681462ff5c5 +Subproject commit a07923c2a6c6965403f8c168e4061fd6eb26e3f8 From c921f8f3572f50b5275524b1779b36c2fd3f9da8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Tue, 5 Nov 2024 10:34:32 +0100 Subject: [PATCH 2/5] update submodule --- src/Umbraco.Web.UI.Client | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client b/src/Umbraco.Web.UI.Client index a07923c2a6..21926435d6 160000 --- a/src/Umbraco.Web.UI.Client +++ b/src/Umbraco.Web.UI.Client @@ -1 +1 @@ -Subproject commit a07923c2a6c6965403f8c168e4061fd6eb26e3f8 +Subproject commit 21926435d6deac0c8e1bf2537577e9a7002a7ba2 From 8e147c2aa7b515c3e297c86fea1863654cd81355 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Tue, 5 Nov 2024 13:32:23 +0100 Subject: [PATCH 3/5] Reintroduce a favicon (#17422) --- templates/UmbracoProject/wwwroot/favicon.ico | Bin 0 -> 5430 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 templates/UmbracoProject/wwwroot/favicon.ico diff --git a/templates/UmbracoProject/wwwroot/favicon.ico b/templates/UmbracoProject/wwwroot/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..63e859b476eff5055e0e557aaa151ca8223fbeef GIT binary patch literal 5430 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 Date: Wed, 6 Nov 2024 09:08:35 +0100 Subject: [PATCH 4/5] Bump version --- version.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.json b/version.json index c1612e5d73..e3b150a550 100644 --- a/version.json +++ b/version.json @@ -1,6 +1,6 @@ { "$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/main/src/NerdBank.GitVersioning/version.schema.json", - "version": "15.0.0-rc3", + "version": "15.0.0-rc4", "assemblyVersion": { "precision": "build" }, From a9dd8b00e0666e38a3a153535c7935e9581a8e08 Mon Sep 17 00:00:00 2001 From: Sven Geusens Date: Wed, 6 Nov 2024 15:35:01 +0100 Subject: [PATCH 5/5] Optimize local links migration (#17432) * Make the migration batched and process in paralel * Change log level * More log levels --------- Co-authored-by: Bjarke Berg --- .../Upgrade/V_15_0_0/ConvertLocalLinks.cs | 106 ++++++++++++++++-- 1 file changed, 96 insertions(+), 10 deletions(-) diff --git a/src/Umbraco.Infrastructure/Migrations/Upgrade/V_15_0_0/ConvertLocalLinks.cs b/src/Umbraco.Infrastructure/Migrations/Upgrade/V_15_0_0/ConvertLocalLinks.cs index 10118acf74..20f5c6cd81 100644 --- a/src/Umbraco.Infrastructure/Migrations/Upgrade/V_15_0_0/ConvertLocalLinks.cs +++ b/src/Umbraco.Infrastructure/Migrations/Upgrade/V_15_0_0/ConvertLocalLinks.cs @@ -1,8 +1,10 @@ +using System.Collections.Concurrent; using Microsoft.Extensions.Logging; using NPoco; using Umbraco.Cms.Core; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Models.Editors; +using Umbraco.Cms.Core.Scoping; using Umbraco.Cms.Core.Serialization; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Core.Web; @@ -23,6 +25,7 @@ public class ConvertLocalLinks : MigrationBase private readonly IJsonSerializer _jsonSerializer; private readonly LocalLinkProcessor _localLinkProcessor; private readonly IMediaTypeService _mediaTypeService; + private readonly ICoreScopeProvider _coreScopeProvider; public ConvertLocalLinks( IMigrationContext context, @@ -33,7 +36,8 @@ public class ConvertLocalLinks : MigrationBase ILanguageService languageService, IJsonSerializer jsonSerializer, LocalLinkProcessor localLinkProcessor, - IMediaTypeService mediaTypeService) + IMediaTypeService mediaTypeService, + ICoreScopeProvider coreScopeProvider) : base(context) { _umbracoContextFactory = umbracoContextFactory; @@ -44,6 +48,7 @@ public class ConvertLocalLinks : MigrationBase _jsonSerializer = jsonSerializer; _localLinkProcessor = localLinkProcessor; _mediaTypeService = mediaTypeService; + _coreScopeProvider = coreScopeProvider; } protected override void Migrate() @@ -64,9 +69,9 @@ public class ConvertLocalLinks : MigrationBase var relevantPropertyEditors = contentPropertyTypes.Concat(mediaPropertyTypes).DistinctBy(pt => pt.Id) - .Where(pt => propertyEditorAliases.Contains(pt.PropertyEditorAlias)) - .GroupBy(pt => pt.PropertyEditorAlias) - .ToDictionary(group => group.Key, group => group.ToArray()); + .Where(pt => propertyEditorAliases.Contains(pt.PropertyEditorAlias)) + .GroupBy(pt => pt.PropertyEditorAlias) + .ToDictionary(group => group.Key, group => group.ToArray()); foreach (var propertyEditorAlias in propertyEditorAliases) @@ -120,18 +125,90 @@ public class ConvertLocalLinks : MigrationBase && propertyData.PropertyTypeId == propertyType.Id); List propertyDataDtos = Database.Fetch(sql); - if (propertyDataDtos.Any() is false) + if (propertyDataDtos.Count < 1) { continue; } - foreach (PropertyDataDto propertyDataDto in propertyDataDtos) + var updateBatch = propertyDataDtos.Select(propertyDataDto => + UpdateBatch.For(propertyDataDto, Database.StartSnapshot(propertyDataDto))).ToList(); + + var updatesToSkip = new ConcurrentBag>(); + + var progress = 0; + + void HandleUpdateBatch(UpdateBatch update) { - if (ProcessPropertyDataDto(propertyDataDto, propertyType, languagesById, valueEditor)) + using UmbracoContextReference umbracoContextReference = _umbracoContextFactory.EnsureUmbracoContext(); + + progress++; + if (progress % 100 == 0) { - Database.Update(propertyDataDto); + _logger.LogInformation(" - finíshed {progress} of {total} properties", progress, + updateBatch.Count); + } + + PropertyDataDto propertyDataDto = update.Poco; + + if (ProcessPropertyDataDto(propertyDataDto, propertyType, languagesById, valueEditor) == false) + { + updatesToSkip.Add(update); } } + + if (DatabaseType == DatabaseType.SQLite) + { + // SQLite locks up if we run the migration in parallel, so... let's not. + foreach (UpdateBatch update in updateBatch) + { + HandleUpdateBatch(update); + } + } + else + { + Parallel.ForEachAsync(updateBatch, async (update, token) => + { + //Foreach here, but we need to suppress the flow before each task, but not the actuall await of the task + Task task; + using (ExecutionContext.SuppressFlow()) + { + task = Task.Run( + () => + { + using ICoreScope scope = _coreScopeProvider.CreateCoreScope(); + scope.Complete(); + HandleUpdateBatch(update); + }, + token); + } + + await task; + }).GetAwaiter().GetResult(); + } + + updateBatch.RemoveAll(updatesToSkip.Contains); + + if (updateBatch.Any() is false) + { + _logger.LogDebug(" - no properties to convert, continuing"); + continue; + } + + _logger.LogInformation(" - {totalConverted} properties converted, saving...", updateBatch.Count); + var result = Database.UpdateBatch(updateBatch, new BatchOptions { BatchSize = 100 }); + if (result != updateBatch.Count) + { + throw new InvalidOperationException( + $"The database batch update was supposed to update {updateBatch.Count} property DTO entries, but it updated {result} entries."); + } + + _logger.LogDebug( + "Migration completed for property type: {propertyTypeName} (id: {propertyTypeId}, alias: {propertyTypeAlias}, editor alias: {propertyTypeEditorAlias}) - {updateCount} property DTO entries updated.", + propertyType.Name, + propertyType.Id, + propertyType.Alias, + propertyType.PropertyEditorAlias, + result); } return true; @@ -167,13 +244,22 @@ public class ConvertLocalLinks : MigrationBase property.SetValue(propertyDataDto.Value, culture, segment); var toEditorValue = valueEditor.ToEditor(property, culture, segment); - _localLinkProcessor.ProcessToEditorValue(toEditorValue); + if (_localLinkProcessor.ProcessToEditorValue(toEditorValue) == false) + { + _logger.LogDebug( + " - skipping as no processor modified the data for property data with id: {propertyDataId} (property type: {propertyTypeName}, id: {propertyTypeId}, alias: {propertyTypeAlias})", + propertyDataDto.Id, + propertyType.Name, + propertyType.Id, + propertyType.Alias); + return false; + } var editorValue = _jsonSerializer.Serialize(toEditorValue); var dbValue = valueEditor.FromEditor(new ContentPropertyData(editorValue, null), null); if (dbValue is not string stringValue || stringValue.DetectIsJson() is false) { - _logger.LogError( + _logger.LogWarning( " - value editor did not yield a valid JSON string as FromEditor value property data with id: {propertyDataId} (property type: {propertyTypeName}, id: {propertyTypeId}, alias: {propertyTypeAlias})", propertyDataDto.Id, propertyType.Name,