Merge remote-tracking branch 'origin/v8/dev' into netcore/dev
# Conflicts: # src/Umbraco.Core/Services/UserServiceExtensions.cs # src/Umbraco.Infrastructure/Examine/ContentValueSetBuilder.cs # src/Umbraco.Infrastructure/Runtime/SqlMainDomLock.cs # src/Umbraco.Infrastructure/Search/ExamineComposer.cs # src/Umbraco.PublishedCache.NuCache/DataSource/DatabaseDataSource.cs # src/Umbraco.Tests/UmbracoExamine/IndexInitializer.cs
This commit is contained in:
@@ -3,7 +3,9 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
using Umbraco.Core.Scoping;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Core.Strings;
|
||||
|
||||
@@ -16,23 +18,41 @@ namespace Umbraco.Examine
|
||||
{
|
||||
private readonly UrlSegmentProviderCollection _urlSegmentProviders;
|
||||
private readonly IUserService _userService;
|
||||
private readonly IScopeProvider _scopeProvider;
|
||||
|
||||
private readonly IShortStringHelper _shortStringHelper;
|
||||
|
||||
public ContentValueSetBuilder(PropertyEditorCollection propertyEditors,
|
||||
UrlSegmentProviderCollection urlSegmentProviders,
|
||||
IUserService userService,
|
||||
IShortStringHelper shortStringHelper,
|
||||
IScopeProvider scopeProvider,
|
||||
bool publishedValuesOnly)
|
||||
: base(propertyEditors, publishedValuesOnly)
|
||||
{
|
||||
_urlSegmentProviders = urlSegmentProviders;
|
||||
_userService = userService;
|
||||
_shortStringHelper = shortStringHelper;
|
||||
_scopeProvider = scopeProvider;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override IEnumerable<ValueSet> GetValueSets(params IContent[] content)
|
||||
{
|
||||
Dictionary<int, IProfile> creatorIds;
|
||||
Dictionary<int, IProfile> writerIds;
|
||||
|
||||
// We can lookup all of the creator/writer names at once which can save some
|
||||
// processing below instead of one by one.
|
||||
using (var scope = _scopeProvider.CreateScope())
|
||||
{
|
||||
creatorIds = _userService.GetProfilesById(content.Select(x => x.CreatorId).ToArray())
|
||||
.ToDictionary(x => x.Id, x => x);
|
||||
writerIds = _userService.GetProfilesById(content.Select(x => x.WriterId).ToArray())
|
||||
.ToDictionary(x => x.Id, x => x);
|
||||
scope.Complete();
|
||||
}
|
||||
|
||||
// TODO: There is a lot of boxing going on here and ultimately all values will be boxed by Lucene anyways
|
||||
// but I wonder if there's a way to reduce the boxing that we have to do or if it will matter in the end since
|
||||
// Lucene will do it no matter what? One idea was to create a `FieldValue` struct which would contain `object`, `object[]`, `ValueType` and `ValueType[]`
|
||||
@@ -61,8 +81,8 @@ namespace Umbraco.Examine
|
||||
{"urlName", urlValue?.Yield() ?? Enumerable.Empty<string>()}, //Always add invariant urlName
|
||||
{"path", c.Path?.Yield() ?? Enumerable.Empty<string>()},
|
||||
{"nodeType", c.ContentType.Id.ToString().Yield() ?? Enumerable.Empty<string>()},
|
||||
{"creatorName", (c.GetCreatorProfile(_userService)?.Name ?? "??").Yield() },
|
||||
{"writerName",(c.GetWriterProfile(_userService)?.Name ?? "??").Yield() },
|
||||
{"creatorName", (creatorIds.TryGetValue(c.CreatorId, out var creatorProfile) ? creatorProfile.Name : "??").Yield() },
|
||||
{"writerName", (writerIds.TryGetValue(c.WriterId, out var writerProfile) ? writerProfile.Name : "??").Yield() },
|
||||
{"writerID", new object[] {c.WriterId}},
|
||||
{"templateID", new object[] {c.TemplateId ?? 0}},
|
||||
{UmbracoExamineFieldNames.VariesByCultureFieldName, new object[] {"n"}},
|
||||
|
||||
@@ -15,6 +15,48 @@ namespace Umbraco.Core.Persistence
|
||||
/// </summary>
|
||||
public static partial class NPocoDatabaseExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Iterates over the result of a paged data set with a db reader
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="database"></param>
|
||||
/// <param name="pageSize">
|
||||
/// The number of rows to load per page
|
||||
/// </param>
|
||||
/// <param name="sql"></param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// NPoco's normal Page returns a List{T} but sometimes we don't want all that in memory and instead want to
|
||||
/// iterate over each row with a reader using Query vs Fetch.
|
||||
/// </remarks>
|
||||
public static IEnumerable<T> QueryPaged<T>(this IDatabase database, long pageSize, Sql sql)
|
||||
{
|
||||
var sqlString = sql.SQL;
|
||||
var sqlArgs = sql.Arguments;
|
||||
|
||||
int? itemCount = null;
|
||||
long pageIndex = 0;
|
||||
do
|
||||
{
|
||||
// Get the paged queries
|
||||
database.BuildPageQueries<T>(pageIndex * pageSize, pageSize, sqlString, ref sqlArgs, out var sqlCount, out var sqlPage);
|
||||
|
||||
// get the item count once
|
||||
if (itemCount == null)
|
||||
{
|
||||
itemCount = database.ExecuteScalar<int>(sqlCount, sqlArgs);
|
||||
}
|
||||
pageIndex++;
|
||||
|
||||
// iterate over rows without allocating all items to memory (Query vs Fetch)
|
||||
foreach (var row in database.Query<T>(sqlPage, sqlArgs))
|
||||
{
|
||||
yield return row;
|
||||
}
|
||||
|
||||
} while ((pageIndex * pageSize) < itemCount);
|
||||
}
|
||||
|
||||
// NOTE
|
||||
//
|
||||
// proper way to do it with TSQL and SQLCE
|
||||
|
||||
@@ -43,6 +43,12 @@ namespace Umbraco.Core.Runtime
|
||||
|
||||
public async Task<bool> AcquireLockAsync(int millisecondsTimeout)
|
||||
{
|
||||
if (!_dbFactory.Configured)
|
||||
{
|
||||
// if we aren't configured, then we're in an install state, in which case we have no choice but to assume we can acquire
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(_dbFactory.SqlContext.SqlSyntax is SqlServerSyntaxProvider sqlServerSyntaxProvider))
|
||||
throw new NotSupportedException("SqlMainDomLock is only supported for Sql Server");
|
||||
|
||||
@@ -129,6 +135,12 @@ namespace Umbraco.Core.Runtime
|
||||
// poll every 1 second
|
||||
Thread.Sleep(1000);
|
||||
|
||||
if (!_dbFactory.Configured)
|
||||
{
|
||||
// if we aren't configured, we just keep looping since we can't query the db
|
||||
continue;
|
||||
}
|
||||
|
||||
lock (_locker)
|
||||
{
|
||||
// If cancellation has been requested we will just exit. Depending on timing of the shutdown,
|
||||
@@ -361,41 +373,44 @@ namespace Umbraco.Core.Runtime
|
||||
_cancellationTokenSource.Cancel();
|
||||
_cancellationTokenSource.Dispose();
|
||||
|
||||
var db = GetDatabase();
|
||||
try
|
||||
if (_dbFactory.Configured)
|
||||
{
|
||||
db.BeginTransaction(IsolationLevel.ReadCommitted);
|
||||
|
||||
// get a write lock
|
||||
_sqlServerSyntax.WriteLock(db, Constants.Locks.MainDom);
|
||||
|
||||
// When we are disposed, it means we have released the MainDom lock
|
||||
// and called all MainDom release callbacks, in this case
|
||||
// if another maindom is actually coming online we need
|
||||
// to signal to the MainDom coming online that we have shutdown.
|
||||
// To do that, we update the existing main dom DB record with a suffixed "_updated" string.
|
||||
// Otherwise, if we are just shutting down, we want to just delete the row.
|
||||
if (_mainDomChanging)
|
||||
var db = GetDatabase();
|
||||
try
|
||||
{
|
||||
_logger.Debug<SqlMainDomLock>("Releasing MainDom, updating row, new application is booting.");
|
||||
db.Execute($"UPDATE umbracoKeyValue SET [value] = [value] + '{UpdatedSuffix}' WHERE [key] = @key", new { key = MainDomKey });
|
||||
db.BeginTransaction(IsolationLevel.ReadCommitted);
|
||||
|
||||
// get a write lock
|
||||
_sqlServerSyntax.WriteLock(db, Constants.Locks.MainDom);
|
||||
|
||||
// When we are disposed, it means we have released the MainDom lock
|
||||
// and called all MainDom release callbacks, in this case
|
||||
// if another maindom is actually coming online we need
|
||||
// to signal to the MainDom coming online that we have shutdown.
|
||||
// To do that, we update the existing main dom DB record with a suffixed "_updated" string.
|
||||
// Otherwise, if we are just shutting down, we want to just delete the row.
|
||||
if (_mainDomChanging)
|
||||
{
|
||||
_logger.Debug<SqlMainDomLock>("Releasing MainDom, updating row, new application is booting.");
|
||||
db.Execute($"UPDATE umbracoKeyValue SET [value] = [value] + '{UpdatedSuffix}' WHERE [key] = @key", new { key = MainDomKey });
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Debug<SqlMainDomLock>("Releasing MainDom, deleting row, application is shutting down.");
|
||||
db.Execute("DELETE FROM umbracoKeyValue WHERE [key] = @key", new { key = MainDomKey });
|
||||
}
|
||||
}
|
||||
else
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Debug<SqlMainDomLock>("Releasing MainDom, deleting row, application is shutting down.");
|
||||
db.Execute("DELETE FROM umbracoKeyValue WHERE [key] = @key", new { key = MainDomKey });
|
||||
ResetDatabase();
|
||||
_logger.Error<SqlMainDomLock>(ex, "Unexpected error during dipsose.");
|
||||
_hasError = true;
|
||||
}
|
||||
finally
|
||||
{
|
||||
db?.CompleteTransaction();
|
||||
ResetDatabase();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ResetDatabase();
|
||||
_logger.Error<SqlMainDomLock>(ex, "Unexpected error during dipsose.");
|
||||
_hasError = true;
|
||||
}
|
||||
finally
|
||||
{
|
||||
db?.CompleteTransaction();
|
||||
ResetDatabase();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ using Umbraco.Core;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
using Umbraco.Core.Scoping;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Core.Strings;
|
||||
using Umbraco.Examine;
|
||||
@@ -30,13 +31,14 @@ namespace Umbraco.Web.Search
|
||||
|
||||
composition.Register<IndexRebuilder>(Lifetime.Singleton);
|
||||
composition.RegisterUnique<IUmbracoIndexConfig, UmbracoIndexConfig>();
|
||||
composition.RegisterUnique<IIndexDiagnosticsFactory, IndexDiagnosticsFactory>();
|
||||
composition.RegisterUnique<IIndexDiagnosticsFactory, IndexDiagnosticsFactory>();
|
||||
composition.RegisterUnique<IPublishedContentValueSetBuilder>(factory =>
|
||||
new ContentValueSetBuilder(
|
||||
factory.GetInstance<PropertyEditorCollection>(),
|
||||
factory.GetInstance<UrlSegmentProviderCollection>(),
|
||||
factory.GetInstance<IUserService>(),
|
||||
factory.GetInstance<IShortStringHelper>(),
|
||||
factory.GetInstance<IScopeProvider>(),
|
||||
true));
|
||||
composition.RegisterUnique<IContentValueSetBuilder>(factory =>
|
||||
new ContentValueSetBuilder(
|
||||
@@ -44,6 +46,7 @@ namespace Umbraco.Web.Search
|
||||
factory.GetInstance<UrlSegmentProviderCollection>(),
|
||||
factory.GetInstance<IUserService>(),
|
||||
factory.GetInstance<IShortStringHelper>(),
|
||||
factory.GetInstance<IScopeProvider>(),
|
||||
false));
|
||||
composition.RegisterUnique<IValueSetBuilder<IMedia>, MediaValueSetBuilder>();
|
||||
composition.RegisterUnique<IValueSetBuilder<IMember>, MemberValueSetBuilder>();
|
||||
|
||||
Reference in New Issue
Block a user