Skip to content

Commit

Permalink
RavenDB-5395 removing support for replacing map-reduce indexes with '…
Browse files Browse the repository at this point in the history
…minimum etag to replace' strategy
  • Loading branch information
ppekrol committed Oct 4, 2016
1 parent 925c176 commit ca5e045
Show file tree
Hide file tree
Showing 8 changed files with 107 additions and 16 deletions.
Expand Up @@ -348,6 +348,9 @@ public async Task<string[]> DirectPutIndexesAsync(IndexToAdd[] indexesToAdd, Ope

public async Task<string[]> DirectPutSideBySideIndexesAsync(IndexToAdd[] indexesToAdd, OperationMetadata operationMetadata, Etag minimumEtagBeforeReplace, DateTime? replaceTimeUtc, CancellationToken token = default(CancellationToken))
{
if (minimumEtagBeforeReplace != null && indexesToAdd != null && indexesToAdd.Any(x => x.Definition.IsMapReduce))
throw new InvalidOperationException("We do not support side-by-side execution for Map-Reduce indexes when 'minimum last indexed etag' scenario is used.");

var sideBySideIndexes = new SideBySideIndexes
{
IndexesToAdd = indexesToAdd,
Expand Down
Expand Up @@ -226,12 +226,14 @@ public void Execute(IDocumentStore store)
/// </summary>
/// <param name="databaseCommands"></param>
/// <param name="documentConvention"></param>
/// <param name="minimumEtagBeforeReplace">The minimum etag after which indexes will be swapped.</param>
/// <param name="minimumEtagBeforeReplace">The minimum etag after which indexes will be swapped (map indexes only).</param>
/// <param name="replaceTimeUtc">The minimum time after which indexes will be swapped.</param>
public virtual void SideBySideExecute(IDatabaseCommands databaseCommands, DocumentConvention documentConvention, Etag minimumEtagBeforeReplace = null, DateTime? replaceTimeUtc = null)
{
Conventions = documentConvention;
var indexDefinition = CreateIndexDefinition();
if (minimumEtagBeforeReplace != null && indexDefinition.IsMapReduce)
throw new InvalidOperationException("We do not support side-by-side execution for Map-Reduce indexes when 'minimum last indexed etag' scenario is used.");

var replaceIndexName = Constants.SideBySideIndexNamePrefix + IndexName;
//check if side by side index exists
Expand Down Expand Up @@ -426,6 +428,8 @@ public virtual async Task SideBySideExecuteAsync(IAsyncDatabaseCommands asyncDat
{
Conventions = documentConvention;
var indexDefinition = CreateIndexDefinition();
if (minimumEtagBeforeReplace != null && indexDefinition.IsMapReduce)
throw new InvalidOperationException("We do not support side-by-side execution for Map-Reduce indexes when 'minimum last indexed etag' scenario is used.");

var replaceIndexName = Constants.SideBySideIndexNamePrefix + IndexName;
//check if side by side index exists
Expand Down
10 changes: 5 additions & 5 deletions Raven.Client.Lightweight/Indexes/IndexCreation.cs
Expand Up @@ -226,7 +226,7 @@ public static async Task CreateIndexesAsync(ExportProvider catalogToGetnIndexing
/// </summary>
/// <param name="assemblyToScanForIndexingTasks">The assembly to scan for indexing tasks.</param>
/// <param name="documentStore">The document store.</param>
/// <param name="minimumEtagBeforeReplace">The minimum etag after which indexes will be swapped.</param>
/// <param name="minimumEtagBeforeReplace">The minimum etag after which indexes will be swapped (map indexes only).</param>
/// <param name="replaceTimeUtc">The minimum time after which indexes will be swapped.</param>
public static void SideBySideCreateIndexes(Assembly assemblyToScanForIndexingTasks, IDocumentStore documentStore, Etag minimumEtagBeforeReplace = null, DateTime? replaceTimeUtc = null)
{
Expand Down Expand Up @@ -324,7 +324,7 @@ public static async Task SideBySideCreateIndexesAsync(ExportProvider catalogToGe
/// </summary>
/// <param name="catalogToGetnIndexingTasksFrom">The catalog to get indexing tasks from.</param>
/// <param name="documentStore">The document store.</param>
/// <param name="minimumEtagBeforeReplace">The minimum etag after which indexes will be swapped.</param>
/// <param name="minimumEtagBeforeReplace">The minimum etag after which indexes will be swapped (map indexes only).</param>
/// <param name="replaceTimeUtc">The minimum time after which indexes will be swapped.</param>
public static void SideBySideCreateIndexes(ExportProvider catalogToGetnIndexingTasksFrom, IDocumentStore documentStore, Etag minimumEtagBeforeReplace = null, DateTime? replaceTimeUtc = null)
{
Expand Down Expand Up @@ -365,7 +365,7 @@ public static void SideBySideCreateIndexes(ExportProvider catalogToGetnIndexingT
/// </summary>
/// <param name="assemblyToScanForIndexingTasks">The assembly to scan for indexing tasks.</param>
/// <param name="documentStore">The document store.</param>
/// <param name="minimumEtagBeforeReplace">The minimum etag after which indexes will be swapped.</param>
/// <param name="minimumEtagBeforeReplace">The minimum etag after which indexes will be swapped (map indexes only).</param>
/// <param name="replaceTimeUtc">The minimum time after which indexes will be swapped.</param>
public static Task SideBySideCreateIndexesAsync(Assembly assemblyToScanForIndexingTasks, IDocumentStore documentStore, Etag minimumEtagBeforeReplace = null, DateTime? replaceTimeUtc = null)
{
Expand All @@ -378,7 +378,7 @@ public static Task SideBySideCreateIndexesAsync(Assembly assemblyToScanForIndexi
/// </summary>
/// <param name="catalogToGetnIndexingTasksFrom">The catalog to get indexing tasks from.</param>
/// <param name="documentStore">The document store.</param>
/// <param name="minimumEtagBeforeReplace">The minimum etag after which indexes will be swapped.</param>
/// <param name="minimumEtagBeforeReplace">The minimum etag after which indexes will be swapped (map indexes only).</param>
/// <param name="replaceTimeUtc">The minimum time after which indexes will be swapped.</param>
public static async Task SideBySideCreateIndexesAsync(ExportProvider catalogToGetnIndexingTasksFrom, IDocumentStore documentStore, Etag minimumEtagBeforeReplace = null, DateTime? replaceTimeUtc = null)
{
Expand All @@ -391,7 +391,7 @@ public static async Task SideBySideCreateIndexesAsync(ExportProvider catalogToGe
.ToList();

var indexesToAdd = CreateIndexesToAdd(tasks, documentStore.Conventions);
await documentStore.AsyncDatabaseCommands.PutSideBySideIndexesAsync(indexesToAdd).ConfigureAwait(false);
await documentStore.AsyncDatabaseCommands.PutSideBySideIndexesAsync(indexesToAdd, minimumEtagBeforeReplace, replaceTimeUtc).ConfigureAwait(false);

foreach (var task in tasks)
await task.AfterExecuteAsync(documentStore.AsyncDatabaseCommands, documentStore.Conventions).ConfigureAwait(false);
Expand Down
11 changes: 3 additions & 8 deletions Raven.Database/Indexing/IndexReplacer.cs
Expand Up @@ -177,12 +177,7 @@ private bool ShouldReplace(IndexReplaceInformation indexReplaceInformation, int
var replaceIndex = Database.IndexStorage.GetIndexInstance(indexId);
var statistics = accessor.Indexing.GetIndexStats(indexId);
if (replaceIndex.IsMapReduce)
{
if (statistics.LastReducedEtag != null && EtagUtil.IsGreaterThanOrEqual(statistics.LastReducedEtag, indexReplaceInformation.MinimumEtagBeforeReplace))
shouldReplace = true;
}
else
if (replaceIndex.IsMapReduce == false)
{
if (statistics.LastIndexedEtag != null && EtagUtil.IsGreaterThanOrEqual(statistics.LastIndexedEtag, indexReplaceInformation.MinimumEtagBeforeReplace))
shouldReplace = true;
Expand Down Expand Up @@ -306,11 +301,11 @@ private void HandleIndexReplaceError(IndexReplaceInformation indexReplaceInforma
}
}

var message = string.Format("Index replace failed. Could not replace index '{0}' with '{1}'.", indexReplaceInformation.IndexToReplace, indexReplaceInformation.ReplaceIndex);
var message = string.Format("Index replace failed. Could not replace index '{0}' with '{1}'. Number of tries: '{2}'.", indexReplaceInformation.IndexToReplace, indexReplaceInformation.ReplaceIndex, indexReplaceInformation.ErrorCount);

Database.AddAlert(new Alert
{
AlertLevel = AlertLevel.Error,
AlertLevel = indexReplaceInformation.ErrorCount <= 10 ? AlertLevel.Warning : AlertLevel.Error,
CreatedAt = SystemTime.UtcNow,
Message = message,
Title = "Index replace failed",
Expand Down
Expand Up @@ -13,6 +13,7 @@ class replaceIndexDialog extends dialogViewModelBase {
private etagMode = ko.observable<boolean>(false);
private dateMode = ko.observable<boolean>(false);
private lastIndexedEtag = ko.observable<string>();
private canAccessEtagMode = ko.observable<boolean>(false);

private replaceDate = ko.observable<Moment>(moment(new Date()));
private replaceDateText = ko.computed(() => {
Expand Down Expand Up @@ -42,7 +43,8 @@ class replaceIndexDialog extends dialogViewModelBase {

processDbStats(stats: databaseStatisticsDto) {
var oldIndex = stats.Indexes.first(i => i.Name == this.indexName);
this.lastIndexedEtag(oldIndex.LastIndexedEtag);
this.lastIndexedEtag(oldIndex.LastIndexedEtag);
this.canAccessEtagMode(!oldIndex.IsMapReduce);
}

saveReplace() {
Expand Down
Expand Up @@ -13,7 +13,7 @@ <h4 class="modal-title">Replace index: <span data-bind="text: indexName"></span>
<button type="button" class="btn btn-default" disabled="disabled">
<i data-bind="css: { 'fa-check': true }" class="fa fa-fw"></i> When new index become non-stale
</button>
<button type="button" class="btn btn-default" data-bind="click: toggleEtagMode">
<button type="button" class="btn btn-default" data-bind="click: toggleEtagMode, enable: canAccessEtagMode">
<i data-bind="css: { 'fa-check': etagMode() }" class="fa fa-fw"></i> index etag reaches last indexed etag of old index
</button>
<button type="button" class="btn btn-default" data-bind="click: toggleDateMode">
Expand Down
1 change: 1 addition & 0 deletions Raven.Tests.Issues/Raven.Tests.Issues.csproj
Expand Up @@ -566,6 +566,7 @@
<Compile Include="RavenDB_505.cs" />
<Compile Include="RavenDB_514.cs" />
<Compile Include="RavenDB_535.cs" />
<Compile Include="RavenDB_5395.cs" />
<Compile Include="RavenDB_542 .cs" />
<Compile Include="RavenDB_554.cs" />
<Compile Include="RavenDB_556.cs" />
Expand Down
86 changes: 86 additions & 0 deletions Raven.Tests.Issues/RavenDB_5395.cs
@@ -0,0 +1,86 @@
// -----------------------------------------------------------------------
// <copyright file="RavenDB_5395.cs" company="Hibernating Rhinos LTD">
// Copyright (c) Hibernating Rhinos LTD. All rights reserved.
// </copyright>
// -----------------------------------------------------------------------
using System;
using System.Linq;
using Raven.Abstractions.Data;
using Raven.Client.Indexes;
using Raven.Tests.Helpers;
using Xunit;

namespace Raven.Tests.Issues
{
public class RavenDB_5395 : RavenTestBase
{
[Fact]
public void SideBySideIndex_WillThrowIfMinimumEtagIsSpecifiedForMapReduce()
{
using (var store = NewDocumentStore())
{
new OldIndex().SideBySideExecute(store);
new OldMapReduceIndex().SideBySideExecute(store);

new OldIndex().SideBySideExecute(store, minimumEtagBeforeReplace: Etag.Parse(Guid.NewGuid().ToString()));

var e = Assert.Throws<InvalidOperationException>(() =>
{
new OldMapReduceIndex().SideBySideExecute(store, minimumEtagBeforeReplace: Etag.Parse(Guid.NewGuid().ToString()));
});

Assert.Equal(@"We do not support side-by-side execution for Map-Reduce indexes when 'minimum last indexed etag' scenario is used.", e.Message);
}
}

private class Person
{
public string Id { get; set; }

public string FirstName { get; set; }

public string LastName { get; set; }
}

private class OldIndex : AbstractIndexCreationTask<Person>
{
public override string IndexName
{
get { return "The/Index"; }
}

public OldIndex()
{
Map = persons => from person in persons select new { person.FirstName };
}
}

private class OldMapReduceIndex : AbstractIndexCreationTask<Person, OldMapReduceIndex.Result>
{
public class Result
{
public string FirstName { get; set; }

public int Count { get; set; }
}

public OldMapReduceIndex()
{
Map = persons => from p in persons
select new
{
p.FirstName,
Count = 1
};

Reduce = results => from r in results
group r by r.FirstName into g
select new
{
FirstName = g.Key,
Count = g.Sum(x => x.Count)
};
}
}
}
}

0 comments on commit ca5e045

Please sign in to comment.