public async Task DontRevertToConflicted()
        {
            // put at 8:30
            // conflicted at 8:50
            // resolved at 9:10
            // will revert to 9:00

            using (var store1 = GetDocumentStore(options: new Options
            {
                ModifyDatabaseRecord = record =>
                {
                    record.ConflictSolverConfig = new ConflictSolver
                    {
                        ResolveToLatest = false,
                        ResolveByCollection = new Dictionary <string, ScriptResolver>()
                    };
                }
            }))
                using (var store2 = GetDocumentStore())
                {
                    DateTime last = default;
                    await RevisionsHelper.SetupRevisions(Server.ServerStore, store1.Database);

                    using (var session = store2.OpenAsyncSession())
                    {
                        await session.StoreAsync(new Company(), "keep-conflicted-revision-insert-order");

                        await session.SaveChangesAsync();

                        var company = new Company
                        {
                            Name = "Name2"
                        };
                        await session.StoreAsync(company, "foo/bar");

                        await session.SaveChangesAsync();
                    }

                    using (var session = store1.OpenAsyncSession())
                    {
                        var company = new Company
                        {
                            Name = "Name1"
                        };
                        await session.StoreAsync(company, "foo/bar");

                        await session.SaveChangesAsync();

                        var companiesRevisions = await session.Advanced.Revisions.GetForAsync <Company>("foo/bar");

                        Assert.Equal(1, companiesRevisions.Count);
                    }

                    await SetupReplicationAsync(store2, store1);

                    WaitUntilHasConflict(store1, "foo/bar");

                    last = DateTime.UtcNow;

                    using (var session = store1.OpenAsyncSession())
                    {
                        var company = new Company
                        {
                            Name = "Resolver"
                        };
                        await session.StoreAsync(company, "foo/bar");

                        await session.SaveChangesAsync();
                    }

                    var db = await GetDocumentDatabaseInstanceFor(store1);

                    RevertResult result;
                    using (var token = new OperationCancelToken(db.Configuration.Databases.OperationTimeout.AsTimeSpan, db.DatabaseShutdown))
                    {
                        result = (RevertResult)await db.DocumentsStorage.RevisionsStorage.RevertRevisions(last.Add(TimeSpan.FromMinutes(1)), TimeSpan.FromMinutes(60),
                                                                                                          onProgress : null, token : token);
                    }

                    Assert.Equal(4, result.ScannedRevisions);
                    Assert.Equal(2, result.ScannedDocuments);
                    Assert.Equal(0, result.RevertedDocuments);

                    using (var session = store1.OpenAsyncSession())
                    {
                        var companiesRevisions = await session.Advanced.Revisions.GetForAsync <Company>("foo/bar");

                        Assert.Equal(3, companiesRevisions.Count);
                    }
                }
        }
        public async Task GetRevisionsBinEntries(bool useSession)
        {
            using (var store1 = GetDocumentStore())
                using (var store2 = GetDocumentStore())
                {
                    var database = await GetDocumentDatabaseInstanceFor(store1);

                    var database2 = await GetDocumentDatabaseInstanceFor(store2);

                    database.TombstoneCleaner.Subscribe(this);
                    database2.TombstoneCleaner.Subscribe(this);

                    await RevisionsHelper.SetupRevisions(Server.ServerStore, store1.Database, configuration =>
                    {
                        configuration.Collections["Users"].PurgeOnDelete = false;
                    });

                    await RevisionsHelper.SetupRevisions(Server.ServerStore, store2.Database, configuration =>
                    {
                        configuration.Collections["Users"].PurgeOnDelete = false;
                    });
                    await SetupReplicationAsync(store1, store2);

                    var deletedRevisions = await store1.Commands().GetRevisionsBinEntriesAsync(long.MaxValue);

                    Assert.Equal(0, deletedRevisions.Count());

                    var id = "users/1";
                    if (useSession)
                    {
                        var user = new User {
                            Name = "Fitzchak"
                        };
                        for (var i = 0; i < 2; i++)
                        {
                            using (var session = store1.OpenAsyncSession())
                            {
                                await session.StoreAsync(user);

                                await session.SaveChangesAsync();
                            }
                            using (var session = store1.OpenAsyncSession())
                            {
                                session.Delete(user.Id);
                                await session.SaveChangesAsync();
                            }
                        }
                        id += "-A";
                    }
                    else
                    {
                        await store1.Commands().PutAsync(id, null, new User {
                            Name = "Fitzchak"
                        });

                        await store1.Commands().DeleteAsync(id, null);

                        await store1.Commands().PutAsync(id, null, new User {
                            Name = "Fitzchak"
                        });

                        await store1.Commands().DeleteAsync(id, null);
                    }

                    WaitForMarker(store1, store2);
                    var statistics = store2.Maintenance.Send(new GetStatisticsOperation());
                    Assert.Equal(useSession ? 2 : 1, statistics.CountOfDocuments);
                    Assert.Equal(4, statistics.CountOfRevisionDocuments);

                    //sanity
                    deletedRevisions = await store1.Commands().GetRevisionsBinEntriesAsync(long.MaxValue);

                    Assert.Equal(1, deletedRevisions.Count());

                    deletedRevisions = await store2.Commands().GetRevisionsBinEntriesAsync(long.MaxValue);

                    Assert.Equal(1, deletedRevisions.Count());

                    using (var session = store2.OpenAsyncSession())
                    {
                        var users = await session.Advanced.Revisions.GetForAsync <User>(id);

                        Assert.Equal(4, users.Count);
                        Assert.Equal(null, users[0].Name);
                        Assert.Equal("Fitzchak", users[1].Name);
                        Assert.Equal(null, users[2].Name);
                        Assert.Equal("Fitzchak", users[3].Name);

                        // Can get metadata only
                        var revisionsMetadata = await session.Advanced.Revisions.GetMetadataForAsync(id);

                        Assert.Equal(4, revisionsMetadata.Count);
                        Assert.Equal((DocumentFlags.DeleteRevision | DocumentFlags.HasRevisions | DocumentFlags.FromReplication).ToString(), revisionsMetadata[0].GetString(Constants.Documents.Metadata.Flags));
                        Assert.Equal((DocumentFlags.HasRevisions | DocumentFlags.Revision | DocumentFlags.FromReplication).ToString(), revisionsMetadata[1].GetString(Constants.Documents.Metadata.Flags));
                        Assert.Equal((DocumentFlags.DeleteRevision | DocumentFlags.HasRevisions | DocumentFlags.FromReplication).ToString(), revisionsMetadata[2].GetString(Constants.Documents.Metadata.Flags));
                        Assert.Equal((DocumentFlags.HasRevisions | DocumentFlags.Revision | DocumentFlags.FromReplication).ToString(), revisionsMetadata[3].GetString(Constants.Documents.Metadata.Flags));
                    }

                    await store1.Maintenance.SendAsync(new RevisionsTests.DeleteRevisionsOperation(new AdminRevisionsHandler.Parameters
                    {
                        DocumentIds = new[] { id, "users/not/exists" }
                    }));

                    WaitForMarker(store1, store2);

                    statistics = store2.Maintenance.Send(new GetStatisticsOperation());
                    Assert.Equal(useSession ? 3 : 2, statistics.CountOfDocuments);

                    Assert.Equal(0, statistics.CountOfRevisionDocuments);
                }
        }
        public async Task ReplicateExpiredAndDeletedRevisions()
        {
            var revisionsAgeLimit = TimeSpan.FromSeconds(10);

            Action <RevisionsConfiguration> modifyConfiguration = configuration =>
                                                                  configuration.Collections["Users"] = new RevisionsCollectionConfiguration
            {
                Disabled = false,
                MinimumRevisionAgeToKeep = revisionsAgeLimit
            };

            using (var store1 = GetDocumentStore())
                using (var store2 = GetDocumentStore())
                {
                    //setup revisions on both stores and setup replication
                    await RevisionsHelper.SetupRevisions(Server.ServerStore, store1.Database, modifyConfiguration);

                    await RevisionsHelper.SetupRevisions(Server.ServerStore, store2.Database, modifyConfiguration);
                    await SetupReplicationAsync(store1, store2);

                    // create some revisions on store1
                    using (var session = store1.OpenAsyncSession())
                    {
                        await session.StoreAsync(new User
                        {
                            Name = "Aviv"
                        }, "users/1-A");

                        await session.SaveChangesAsync();
                    }

                    for (int i = 2; i <= 10; i++)
                    {
                        using (var session = store1.OpenAsyncSession())
                        {
                            var user = await session.LoadAsync <User>("users/1-A");

                            user.Name = "Aviv" + i;
                            await session.SaveChangesAsync();
                        }
                    }

                    // wait for replication
                    WaitForMarker(store1, store2);

                    using (var session = store2.OpenAsyncSession())
                    {
                        var doc = await session.LoadAsync <User>("users/1-A");

                        Assert.Equal("Aviv10", doc.Name);
                    }

                    // wait until revisions are expired
                    await Task.Delay(revisionsAgeLimit);

                    // modify document
                    using (var session = store1.OpenAsyncSession())
                    {
                        var user = await session.LoadAsync <User>("users/1-A");

                        user.Name = "Grisha";
                        await session.SaveChangesAsync();
                    }

                    WaitForMarker(store1, store2);

                    // expired revisions should be deleted
                    // assert that both stores have just one revision now
                    using (var session = store1.OpenAsyncSession())
                    {
                        var revisions = await session.Advanced.Revisions.GetForAsync <User>("users/1-A");

                        Assert.Equal(1, revisions.Count);
                        Assert.Equal("Grisha", revisions[0].Name);
                    }
                    using (var session = store2.OpenAsyncSession())
                    {
                        var revisions = await session.Advanced.Revisions.GetForAsync <User>("users/1-A");

                        Assert.Equal(1, revisions.Count);
                        Assert.Equal("Grisha", revisions[0].Name);
                    }
                }
        }
Exemple #4
0
        public async Task limitRevisionDeletion()
        {
            using (var store = GetDocumentStore())
            {
                var configuration = new RevisionsConfiguration
                {
                    Default = new RevisionsCollectionConfiguration
                    {
                        Disabled = false,
                        MinimumRevisionsToKeep = 1000000
                    },
                };
                await RevisionsHelper.SetupRevisions(store, Server.ServerStore, configuration);

                using (var session = store.OpenAsyncSession())
                {
                    await session.StoreAsync(new User { Name = "Toli" }, "users/1");

                    await session.StoreAsync(new User { Name = "Mitzi" }, "users/2");

                    await session.StoreAsync(new Order { Employee = "Daniel" }, "orders/1");

                    await session.SaveChangesAsync();
                }

                for (int i = 0; i < 500; i++)
                {
                    using (var session = store.OpenAsyncSession())
                    {
                        await session.StoreAsync(new User { Name = "Toli" + i }, "users/1");

                        await session.StoreAsync(new User { Name = "Mitzi" + i }, "users/2");

                        await session.StoreAsync(new Order { Employee = "Daniel" + i }, "orders/1");

                        await session.SaveChangesAsync();
                    }
                }
                for (int i = 500; i < 630; i++)
                {
                    using (var session = store.OpenAsyncSession())
                    {
                        await session.StoreAsync(new User { Name = "Mitzi" + i }, "users/2");

                        await session.SaveChangesAsync();
                    }
                }

                using (var session = store.OpenAsyncSession())
                {
                    var revisionCount = session.Advanced.Revisions.GetForAsync <User>("users/1", 0, 1000).Result.Count;
                    Assert.Equal(501, revisionCount);
                    revisionCount = session.Advanced.Revisions.GetForAsync <User>("users/2", 0, 1000).Result.Count;
                    Assert.Equal(631, revisionCount);
                    revisionCount = session.Advanced.Revisions.GetForAsync <User>("orders/1", 0, 1000).Result.Count;
                    Assert.Equal(501, revisionCount);
                }

                configuration = new RevisionsConfiguration
                {
                    Default = new RevisionsCollectionConfiguration
                    {
                        Disabled = false,
                        MinimumRevisionsToKeep = 10,
                        MaximumRevisionsToDeleteUponDocumentUpdate = 100
                    },
                    Collections = new Dictionary <string, RevisionsCollectionConfiguration>
                    {
                        ["Orders"] = new RevisionsCollectionConfiguration
                        {
                            Disabled = false,
                            MinimumRevisionsToKeep = 33,
                            MaximumRevisionsToDeleteUponDocumentUpdate = 35
                        }
                    }
                };
                await RevisionsHelper.SetupRevisions(store, Server.ServerStore, configuration);

                using (var session = store.OpenAsyncSession())
                {
                    await session.StoreAsync(new User { Name = "Toli" }, "users/1");

                    await session.StoreAsync(new User { Name = "Toli" }, "users/2");

                    await session.StoreAsync(new Order { Employee = "Toli" }, "orders/1");

                    await session.SaveChangesAsync();

                    var revisionCount = session.Advanced.Revisions.GetForAsync <User>("users/1", 0, 1000).Result.Count;
                    Assert.Equal(402, revisionCount);
                    revisionCount = session.Advanced.Revisions.GetForAsync <User>("users/2", 0, 1000).Result.Count;
                    Assert.Equal(532, revisionCount);
                    revisionCount = session.Advanced.Revisions.GetForAsync <Order>("orders/1", 0, 1000).Result.Count;
                    Assert.Equal(467, revisionCount);
                }

                for (int i = 0; i < 4; i++)
                {
                    using (var session = store.OpenAsyncSession())
                    {
                        await session.StoreAsync(new User { Name = "A" + i }, "users/1");

                        await session.StoreAsync(new User { Name = "B" + i }, "users/2");

                        await session.StoreAsync(new Order { Employee = "C" + i }, "orders/1");

                        await session.SaveChangesAsync();
                    }
                }

                using (var session = store.OpenAsyncSession())
                {
                    var revisionCount = session.Advanced.Revisions.GetForAsync <User>("users/1", 0, 1000).Result.Count;
                    Assert.Equal(10, revisionCount);
                    revisionCount = session.Advanced.Revisions.GetForAsync <User>("users/2", 0, 1000).Result.Count;
                    Assert.Equal(136, revisionCount);
                    revisionCount = session.Advanced.Revisions.GetForAsync <Order>("orders/1", 0, 1000).Result.Count;
                    Assert.Equal(331, revisionCount);
                }

                for (int i = 4; i < 13; i++)
                {
                    using (var session = store.OpenAsyncSession())
                    {
                        await session.StoreAsync(new User { Name = "A" + i }, "users/1");

                        await session.StoreAsync(new User { Name = "B" + i }, "users/2");

                        await session.StoreAsync(new Order { Employee = "C" + i }, "orders/1");

                        await session.SaveChangesAsync();
                    }
                }

                using (var session = store.OpenAsyncSession())
                {
                    var revisionCount = session.Advanced.Revisions.GetForAsync <User>("users/1", 0, 1000).Result.Count;
                    Assert.Equal(10, revisionCount);
                    revisionCount = session.Advanced.Revisions.GetForAsync <User>("users/2", 0, 1000).Result.Count;
                    Assert.Equal(10, revisionCount);
                    revisionCount = session.Advanced.Revisions.GetForAsync <Order>("orders/1", 0, 1000).Result.Count;
                    Assert.Equal(33, revisionCount);
                }
                WaitForUserToContinueTheTest(store);
            }
        }
        public async Task ImportRevisionDocumentsWithoutDocuments()
        {
            var file = Path.Combine(NewDataPath(forceCreateDir: true), Guid.NewGuid().ToString());

            try
            {
                using (var store1 = GetDocumentStore(new Options
                {
                    ModifyDatabaseName = s => $"{s}_store1"
                }))
                {
                    using (var session = store1.OpenAsyncSession())
                    {
                        await RevisionsHelper.SetupRevisions(Server.ServerStore, store1.Database);

                        await session.StoreAsync(new Person { Name = "Name1" });

                        await session.StoreAsync(new Person { Name = "Name2" });

                        await session.StoreAsync(new Company { Name = "Hibernating Rhinos " });

                        await session.SaveChangesAsync();
                    }

                    for (int i = 0; i < 2; i++)
                    {
                        using (var session = store1.OpenAsyncSession())
                        {
                            var company = await session.LoadAsync <Company>("companies/1-A");

                            var person = await session.LoadAsync <Person>("people/1-A");

                            company.Name += " update " + i;
                            person.Name  += " update " + i;
                            await session.StoreAsync(company);

                            await session.StoreAsync(person);

                            await session.SaveChangesAsync();
                        }
                    }

                    using (var session = store1.OpenAsyncSession())
                    {
                        var person = await session.LoadAsync <Person>("people/2-A");

                        Assert.NotNull(person);
                        session.Delete(person);
                        await session.SaveChangesAsync();
                    }
                    var operation = await store1.Smuggler.ExportAsync(new DatabaseSmugglerExportOptions
                    {
                        OperateOnTypes = DatabaseItemType.RevisionDocuments | DatabaseItemType.DatabaseRecord
                    }, file);

                    await operation.WaitForCompletionAsync(TimeSpan.FromMinutes(1));

                    var stats = await store1.Maintenance.SendAsync(new GetStatisticsOperation());

                    Assert.Equal(4, stats.CountOfDocuments);
                    Assert.Equal(8, stats.CountOfRevisionDocuments);
                }

                using (var store2 = GetDocumentStore(new Options
                {
                    ModifyDatabaseName = s => $"{s}_store2"
                }))
                {
                    var operation = await store2.Smuggler.ImportAsync(new DatabaseSmugglerImportOptions(), file);

                    await operation.WaitForCompletionAsync(TimeSpan.FromMinutes(1));

                    var stats = await store2.Maintenance.SendAsync(new GetStatisticsOperation());

                    Assert.Equal(0, stats.CountOfDocuments);
                    Assert.Equal(10, stats.CountOfRevisionDocuments);
                    using (Server.ServerStore.ContextPool.AllocateOperationContext(out JsonOperationContext context))
                    {
                        var command = new GetRevisionsBinEntryCommand(long.MaxValue, 5);
                        await store2.GetRequestExecutor().ExecuteAsync(command, context);

                        Assert.Equal(3, command.Result.Results.Length);
                    }
                }
            }
            finally
            {
                File.Delete(file);
            }
        }
Exemple #6
0
        public async Task PutAttachments()
        {
            using (var store = GetDocumentStore())
            {
                await SetDatabaseId(store, dbId);

                await RevisionsHelper.SetupRevisions(Server.ServerStore, store.Database, configuration =>
                {
                    configuration.Collections["Users"].PurgeOnDelete          = false;
                    configuration.Collections["Users"].MinimumRevisionsToKeep = 4;
                });

                var names = CreateDocumentWithAttachments(store);
                AssertRevisions(store, names, (session, revisions) =>
                {
                    AssertRevisionAttachments(names, 3, revisions[0], session);
                    AssertRevisionAttachments(names, 2, revisions[1], session);
                    AssertRevisionAttachments(names, 1, revisions[2], session);
                    AssertNoRevisionAttachment(revisions[3], session);
                }, 9);

                // Delete document should delete all the attachments
                store.Commands().Delete("users/1", null);
                AssertRevisions(store, names, (session, revisions) =>
                {
                    AssertNoRevisionAttachment(revisions[0], session, true);
                    AssertRevisionAttachments(names, 3, revisions[1], session);
                    AssertRevisionAttachments(names, 2, revisions[2], session);
                    AssertRevisionAttachments(names, 1, revisions[3], session);
                }, 6, expectedCountOfDocuments: 0);

                // Create another revision which should delete old revision
                using (var session = store.OpenSession()) // This will delete the revision #1 which is without attachment
                {
                    session.Store(new User {
                        Name = "Fitzchak 2"
                    }, "users/1");
                    session.SaveChanges();
                }
                AssertRevisions(store, names, (session, revisions) =>
                {
                    AssertNoRevisionAttachment(revisions[0], session);
                    AssertNoRevisionAttachment(revisions[1], session, true);
                    AssertRevisionAttachments(names, 3, revisions[2], session);
                    AssertRevisionAttachments(names, 2, revisions[3], session);
                }, 5);

                using (var session = store.OpenSession()) // This will delete the revision #2 which is with attachment
                {
                    session.Store(new User {
                        Name = "Fitzchak 3"
                    }, "users/1");
                    session.SaveChanges();
                }
                AssertRevisions(store, names, (session, revisions) =>
                {
                    AssertNoRevisionAttachment(revisions[0], session);
                    AssertNoRevisionAttachment(revisions[1], session);
                    AssertNoRevisionAttachment(revisions[2], session, true);
                    AssertRevisionAttachments(names, 3, revisions[3], session);
                }, 3);

                using (var session = store.OpenSession()) // This will delete the revision #3 which is with attachment
                {
                    session.Store(new User {
                        Name = "Fitzchak 4"
                    }, "users/1");
                    session.SaveChanges();
                }
                AssertRevisions(store, names, (session, revisions) =>
                {
                    AssertNoRevisionAttachment(revisions[0], session);
                    AssertNoRevisionAttachment(revisions[1], session);
                    AssertNoRevisionAttachment(revisions[2], session);
                    AssertNoRevisionAttachment(revisions[3], session, true);
                }, 0, expectedCountOfUniqueAttachments: 0);

                using (var session = store.OpenSession()) // This will delete the revision #4 which is with attachment
                {
                    session.Store(new User {
                        Name = "Fitzchak 5"
                    }, "users/1");
                    session.SaveChanges();
                }
                AssertRevisions(store, names, (session, revisions) =>
                {
                    AssertNoRevisionAttachment(revisions[0], session);
                    AssertNoRevisionAttachment(revisions[1], session);
                    AssertNoRevisionAttachment(revisions[2], session);
                    AssertNoRevisionAttachment(revisions[3], session);
                }, 0, expectedCountOfUniqueAttachments: 0);
            }
        }
        public async Task CanExportAndImportAttachmentsAndRevisionAttachments()
        {
            var file = GetTempFileName();

            try
            {
                using (var store1 = GetDocumentStore(new Options
                {
                    ModifyDatabaseName = s => $"{s}_store1"
                }))
                {
                    await SetDatabaseId(store1, new Guid("00000000-48c4-421e-9466-000000000000"));

                    await RevisionsHelper.SetupRevisions(Server.ServerStore, store1.Database, configuration =>
                    {
                        configuration.Collections["Users"].PurgeOnDelete          = false;
                        configuration.Collections["Users"].MinimumRevisionsToKeep = 4;
                    });

                    AttachmentsRevisions.CreateDocumentWithAttachments(store1);
                    using (var bigStream = new MemoryStream(Enumerable.Range(1, 999 * 1024).Select(x => (byte)x).ToArray()))
                        store1.Operations.Send(new PutAttachmentOperation("users/1", "big-file", bigStream, "image/png"));

                    var exportOperation = await store1.Smuggler.ExportAsync(new DatabaseSmugglerExportOptions(), file);

                    var exportResult = (SmugglerResult)exportOperation.WaitForCompletion();

                    Assert.Equal(1, exportResult.Documents.ReadCount);
                    Assert.Equal(4, exportResult.RevisionDocuments.ReadCount);
                    Assert.Equal(4, exportResult.Documents.Attachments.ReadCount);
                    Assert.Equal(10, exportResult.RevisionDocuments.Attachments.ReadCount);

                    var stats = await store1.Maintenance.SendAsync(new GetStatisticsOperation());

                    Assert.Equal(1, stats.CountOfDocuments);
                    Assert.Equal(4, stats.CountOfRevisionDocuments);
                    Assert.Equal(14, stats.CountOfAttachments);
                    Assert.Equal(4, stats.CountOfUniqueAttachments);
                }

                using (var store2 = GetDocumentStore(new Options
                {
                    ModifyDatabaseName = s => $"{s}_store2"
                }))
                {
                    var dbId = new Guid("00000000-48c4-421e-9466-000000000000");
                    await SetDatabaseId(store2, dbId);

                    await RevisionsHelper.SetupRevisions(Server.ServerStore, store2.Database);

                    for (var i = 0; i < 2; i++) // Make sure that we can import attachments twice and it will overwrite
                    {
                        var importOperation = await store2.Smuggler.ImportAsync(new DatabaseSmugglerImportOptions(), file);

                        var importResult = (SmugglerResult)importOperation.WaitForCompletion();

                        Assert.Equal(1, importResult.Documents.ReadCount);
                        Assert.Equal(4, importResult.RevisionDocuments.ReadCount);
                        Assert.Equal(4, importResult.Documents.Attachments.ReadCount);
                        Assert.Equal(4, importResult.RevisionDocuments.Attachments.ReadCount);

                        var stats = await store2.Maintenance.SendAsync(new GetStatisticsOperation());

                        Assert.Equal(1, stats.CountOfDocuments);
                        Assert.Equal(5, stats.CountOfRevisionDocuments);
                        Assert.Equal(14 + 4, stats.CountOfAttachments); // the imported document will create 1 additional revision with 4 attachments
                        Assert.Equal(4, stats.CountOfUniqueAttachments);

                        using (var session = store2.OpenSession())
                        {
                            var readBuffer = new byte[1024 * 1024];
                            using (var attachmentStream = new MemoryStream(readBuffer))
                                using (var attachment = session.Advanced.Attachments.Get("users/1", "big-file"))
                                {
                                    attachment.Stream.CopyTo(attachmentStream);
                                    Assert.Equal("big-file", attachment.Details.Name);
                                    Assert.Equal("zKHiLyLNRBZti9DYbzuqZ/EDWAFMgOXB+SwKvjPAINk=", attachment.Details.Hash);
                                    Assert.Equal(999 * 1024, attachmentStream.Position);
                                    Assert.Equal(Enumerable.Range(1, 999 * 1024).Select(x => (byte)x), readBuffer.Take((int)attachmentStream.Position));
                                }
                        }
                    }
                }
            }
            finally
            {
                File.Delete(file);
            }
        }
Exemple #8
0
        public async Task ExternalReplicationWithRevisionsBin4()
        {
            using (var store1 = GetDocumentStore())

                using (var store2 = GetDocumentStore())
                {
                    await RevisionsHelper.SetupRevisions(Server.ServerStore, store2.Database, modifyConfiguration : configuration => configuration.Collections["Users"].PurgeOnDelete = true);

                    var externalTask = new ExternalReplication(store2.Database, "ExternalReplication");
                    await AddWatcherToReplicationTopology(store1, externalTask);

                    using (var s1 = store1.OpenSession())
                    {
                        s1.Store(new User()
                        {
                            Name = "Toli"
                        }, "foo/bar");
                        s1.SaveChanges();
                    }

                    Assert.True(WaitForDocument(store2, "foo/bar"));
                    for (int i = 0; i < 4; i++)
                    {
                        var name = "Toli" + i;
                        using (var s1 = store1.OpenSession())
                        {
                            s1.Store(new User()
                            {
                                Name = name
                            }, "foo/bar");
                            s1.SaveChanges();
                        }

                        await WaitForValueAsync(async() =>
                        {
                            using (var s2 = store2.OpenAsyncSession())
                            {
                                var user = await s2.LoadAsync <User>("foo/bar");
                                return(name.Equals(user.Name, StringComparison.InvariantCultureIgnoreCase));
                            }
                        }, true);
                    }

                    using (var s1 = store1.OpenSession())
                    {
                        s1.Delete("foo/bar");
                        s1.SaveChanges();
                    }
                    await WaitForValueAsync(async() =>
                    {
                        using (var s2 = store2.OpenAsyncSession())
                        {
                            var user = await s2.LoadAsync <User>("foo/bar");
                            return(user == null);
                        }
                    }, true);

                    var database = await Server.ServerStore.DatabasesLandlord.TryGetOrCreateResourceStore(store2.Database);

                    var revisionsStorage = database.DocumentsStorage.RevisionsStorage;
                    using (database.DocumentsStorage.ContextPool.AllocateOperationContext(out DocumentsOperationContext context))
                        using (context.OpenReadTransaction())
                        {
                            var revisions = revisionsStorage.GetRevisionsBinEntries(context, long.MaxValue, 6).Count();
                            Assert.Equal(0, revisions);
                        }

                    database = await Server.ServerStore.DatabasesLandlord.TryGetOrCreateResourceStore(store1.Database);

                    revisionsStorage = database.DocumentsStorage.RevisionsStorage;
                    using (database.DocumentsStorage.ContextPool.AllocateOperationContext(out DocumentsOperationContext context))
                        using (context.OpenReadTransaction())
                        {
                            var revisions = revisionsStorage.GetRevisionsBinEntries(context, long.MaxValue, 6).Count();
                            Assert.Equal(0, revisions);
                        }
                }
        }
Exemple #9
0
        public async Task CanMigrateFromRavenDb()
        {
            var file = Path.Combine(NewDataPath(forceCreateDir: true), "export.ravendbdump");
            var id   = "users/1";

            using (var store1 = GetDocumentStore())
            {
                await RevisionsHelper.SetupRevisions(Server.ServerStore, store1.Database);

                using (var session = store1.OpenAsyncSession())
                {
                    await session.StoreAsync(new User
                    {
                        Name = "Egor"
                    }, id);

                    {
                        session.CountersFor(id).Increment("Downloads", int.MaxValue);
                        session.CountersFor(id).Increment("ShouldBePositiveValueAfterSmuggler", long.MaxValue);
                        session.CountersFor(id).Increment("LittleCounter", 500);
                    }
                    await session.SaveChangesAsync();
                }
                for (int i = 0; i < 10; i++)
                {
                    using (var session = store1.OpenAsyncSession())
                    {
                        var user = await session.LoadAsync <Company>(id);

                        user.Name = "Egor " + i;
                        await session.SaveChangesAsync();
                    }
                }
                using (var session = store1.OpenAsyncSession())
                {
                    var revisionsMetadata = await session.Advanced.Revisions.GetMetadataForAsync(id);

                    Assert.Equal(12, revisionsMetadata.Count);
                }
                var operation = await store1.Smuggler.ExportAsync(new DatabaseSmugglerExportOptions(), file);

                await operation.WaitForCompletionAsync(TimeSpan.FromMinutes(1));
            }
            // all data import
            using (var store2 = GetDocumentStore())
            {
                var operation = await store2.Smuggler.ImportAsync(new DatabaseSmugglerImportOptions(), file);

                await operation.WaitForCompletionAsync(TimeSpan.FromMinutes(1));

                using (var session = store2.OpenAsyncSession())
                {
                    var metadata = session.Advanced.GetMetadataFor(await session.LoadAsync <User>(id));
                    Assert.Equal("HasRevisions, HasCounters", metadata.GetString("@flags"));
                    var revisionsMetadata = await session.Advanced.Revisions.GetMetadataForAsync(id);

                    Assert.Equal(13, revisionsMetadata.Count);  // +1 revision added when importing
                    var dic = await session.CountersFor(id).GetAllAsync();

                    Assert.Equal(3, dic.Count);
                    Assert.Equal(int.MaxValue, dic["Downloads"]);
                    Assert.Equal(long.MaxValue, dic["ShouldBePositiveValueAfterSmuggler"]);
                    Assert.Equal(500, dic["LittleCounter"]);
                }
            }

            // no DatabaseRecord, no RevisionDocuments, no Counters
            using (var store3 = GetDocumentStore())
            {
                var importOptions = new DatabaseSmugglerImportOptions();
                importOptions.OperateOnTypes -= DatabaseItemType.DatabaseRecord;
                importOptions.OperateOnTypes -= DatabaseItemType.RevisionDocuments;
                importOptions.OperateOnTypes -= DatabaseItemType.Counters;

                var operation = await store3.Smuggler.ImportAsync(importOptions, file);

                await operation.WaitForCompletionAsync(TimeSpan.FromMinutes(1));

                using (var session = store3.OpenAsyncSession())
                {
                    var metadata = session.Advanced.GetMetadataFor(await session.LoadAsync <User>(id));
                    Assert.False(metadata.ContainsKey("@flags"));
                    Assert.False(metadata.ContainsKey("@counters"));
                    var revisionsMetadata = await session.Advanced.Revisions.GetMetadataForAsync(id);

                    Assert.Equal(0, revisionsMetadata.Count);  // +1 revision added when importing
                    var dic = await session.CountersFor(id).GetAllAsync();

                    Assert.Equal(0, dic.Count);
                }
            }

            // if doc has counters AND revisions => they must be kept.
            using (var store4 = GetDocumentStore())
            {
                await RevisionsHelper.SetupRevisions(Server.ServerStore, store4.Database);

                using (var session = store4.OpenAsyncSession())
                {
                    await session.StoreAsync(new User
                    {
                        Name = "Egor"
                    }, id);

                    {
                        session.CountersFor(id).Increment("ShouldBeKeptAfterSmugglerImport", 322);
                    }
                    await session.SaveChangesAsync();
                }
                var importOptions = new DatabaseSmugglerImportOptions();
                importOptions.OperateOnTypes -= DatabaseItemType.DatabaseRecord;
                importOptions.OperateOnTypes -= DatabaseItemType.RevisionDocuments;
                importOptions.OperateOnTypes -= DatabaseItemType.Counters;

                var operation = await store4.Smuggler.ImportAsync(importOptions, file);

                await operation.WaitForCompletionAsync(TimeSpan.FromMinutes(1));

                using (var session = store4.OpenAsyncSession())
                {
                    var user = await session.LoadAsync <User>(id);

                    Assert.Equal("Egor 9", user.Name);   // check if document changed.
                    var metadata = session.Advanced.GetMetadataFor(user);
                    Assert.Equal("HasRevisions, HasCounters", metadata.GetString("@flags"));
                    var revisionsMetadata = await session.Advanced.Revisions.GetMetadataForAsync(id);

                    Assert.Equal(3, revisionsMetadata.Count);  // +1 revision added when importing
                    var dic = await session.CountersFor(id).GetAllAsync();

                    Assert.Equal(1, dic.Count);
                    Assert.Equal(322, dic["ShouldBeKeptAfterSmugglerImport"]);
                }
            }
        }
Exemple #10
0
        public async Task Can_handle_delete_revision_of_doc_that_changed_collection()
        {
            using (var store = GetDocumentStore())
            {
                // setup revision with PurgeOnDelete = false
                var index = await RevisionsHelper.SetupRevisions(Server.ServerStore, store.Database, new RevisionsConfiguration
                {
                    Default = new RevisionsCollectionConfiguration()
                });

                var documentDatabase = await Server.ServerStore.DatabasesLandlord.TryGetOrCreateResourceStore(store.Database);

                await documentDatabase.RachisLogIndexNotifications.WaitForIndexNotification(index, Server.ServerStore.Engine.OperationTimeout);

                // store a document "users/1" under 'Users' collection
                // and create some revisions for it
                using (var session = store.OpenAsyncSession())
                {
                    var user = new User {
                        Name = "Aviv "
                    };
                    await session.StoreAsync(user, "users/1");

                    await session.SaveChangesAsync();
                }

                for (int i = 0; i < 9; i++)
                {
                    using (var session = store.OpenAsyncSession())
                    {
                        var user = await session.LoadAsync <User>("users/1");

                        user.Name += i;
                        await session.StoreAsync(user);

                        await session.SaveChangesAsync();
                    }
                }

                using (var session = store.OpenAsyncSession())
                {
                    var revisions = await session.Advanced.Revisions.GetForAsync <User>("users/1");

                    Assert.Equal(10, revisions.Count);
                }

                // delete document "users/1"
                using (var session = store.OpenSession())
                {
                    session.Delete("users/1");
                    session.SaveChanges();
                }

                using (var session = store.OpenAsyncSession())
                {
                    var revisions = await session.Advanced.Revisions.GetForAsync <User>("users/1");

                    Assert.Equal(11, revisions.Count);
                }

                // store a new document with the same id - "users/1"
                // but under 'Companies' collection
                using (var session = store.OpenAsyncSession())
                {
                    var company = new Company {
                        Name = "HR "
                    };
                    await session.StoreAsync(company, "users/1");

                    await session.SaveChangesAsync();
                }

                using (var session = store.OpenAsyncSession())
                {
                    var revisions = await session.Advanced.Revisions.GetForAsync <object>("users/1");

                    Assert.Equal(12, revisions.Count);
                }

                // enable PurgeOnDelete
                var configuration = new RevisionsConfiguration
                {
                    Default = new RevisionsCollectionConfiguration
                    {
                        PurgeOnDelete = true
                    }
                };

                index = await RevisionsHelper.SetupRevisions(Server.ServerStore, store.Database, configuration);

                await documentDatabase.RachisLogIndexNotifications.WaitForIndexNotification(index, Server.ServerStore.Engine.OperationTimeout);

                // make sure we don't have a tombstone for "users/1"
                await documentDatabase.TombstoneCleaner.ExecuteCleanup();

                // delete document "users/1"
                using (var session = store.OpenSession())
                {
                    session.Delete("users/1");
                    session.SaveChanges();
                }

                // all the revisions for "users/1" should be deleted -
                // the old ones ('Users' collection) as well as the new ones ('Companies' collection)
                using (var session = store.OpenAsyncSession())
                {
                    var revisions = await session.Advanced.Revisions.GetForAsync <object>("users/1");

                    Assert.Empty(revisions);
                }
            }
        }
Exemple #11
0
        public async Task ShouldPreserveTombstoneFlagsAfterRestore()
        {
            using (var store = GetDocumentStore())
            {
                var configuration = new RevisionsConfiguration
                {
                    Default = new RevisionsCollectionConfiguration
                    {
                        Disabled = false,
                        MinimumRevisionsToKeep = 10
                    },

                    Collections = new Dictionary <string, RevisionsCollectionConfiguration>
                    {
                        ["Users"] = new RevisionsCollectionConfiguration
                        {
                            Disabled = false,
                            MinimumRevisionsToKeep = 5
                        }
                    }
                };

                await RevisionsHelper.SetupRevisions(store, Server.ServerStore, configuration);

                using (var session = store.OpenSession())
                {
                    session.Store(new User()
                    {
                        Name = "Arek"
                    }, "users/arek");

                    session.SaveChanges();
                }

                using (var session = store.OpenSession())
                {
                    session.Delete("users/arek"); // this will create tombstone with HasRevisions flags

                    session.SaveChanges();
                }

                var backupPath = NewDataPath(suffix: "BackupFolder");

                var config       = Backup.CreateBackupConfiguration(backupPath);
                var backupTaskId = await Backup.UpdateConfigAndRunBackupAsync(Server, config, store);

                // restore

                var backupDirectory = Directory.GetDirectories(backupPath).First();

                var databaseName = GetDatabaseName() + "restore";

                var files = Directory.GetFiles(backupDirectory)
                            .Where(BackupUtils.IsBackupFile)
                            .OrderBackups()
                            .ToArray();

                RestoreBackupConfiguration config2 = new RestoreBackupConfiguration()
                {
                    BackupLocation        = backupDirectory,
                    DatabaseName          = databaseName,
                    LastFileNameToRestore = files.Last()
                };

                RestoreBackupOperation restoreOperation = new RestoreBackupOperation(config2);
                await store.Maintenance.Server.Send(restoreOperation)
                .WaitForCompletionAsync(TimeSpan.FromSeconds(30));

                using (var storeOfRestoredDb = GetDocumentStore(new Options()
                {
                    CreateDatabase = false, ModifyDatabaseName = s => databaseName
                }))
                {
                    var db = await GetDatabase(storeOfRestoredDb.Database);

                    using (db.DocumentsStorage.ContextPool.AllocateOperationContext(out DocumentsOperationContext ctx))
                        using (ctx.OpenReadTransaction())
                        {
                            var tombstones = db.DocumentsStorage.GetTombstonesFrom(ctx, 0, 0, int.MaxValue).ToList();

                            Assert.Equal(1, tombstones.Count);
                            Assert.Equal(DocumentFlags.HasRevisions, tombstones[0].Flags);
                        }
                }
            }
        }
        public async Task CanExportAndImportAttachmentsAndRevisionAttachments()
        {
            var file = Path.GetTempFileName();

            try
            {
                using (var store1 = GetDocumentStore(new Options
                {
                    ModifyDatabaseName = s => $"{s}_store1"
                }))
                {
                    await SetDatabaseId(store1, new Guid("00000000-48c4-421e-9466-000000000000"));

                    await RevisionsHelper.SetupRevisions(Server.ServerStore, store1.Database, false, 4);

                    AttachmentsRevisions.CreateDocumentWithAttachments(store1);
                    using (var bigStream = new MemoryStream(Enumerable.Range(1, 999 * 1024).Select(x => (byte)x).ToArray()))
                        store1.Operations.Send(new PutAttachmentOperation("users/1", "big-file", bigStream, "image/png"));

                    /*var result = */
                    await store1.Smuggler.ExportAsync(new DatabaseSmugglerExportOptions(), file);

                    // TODO: RavenDB-6936 store.Smuggler.Export and Import method should return the SmugglerResult

                    var stats = await store1.Admin.SendAsync(new GetStatisticsOperation());

                    Assert.Equal(1, stats.CountOfDocuments);
                    Assert.Equal(4, stats.CountOfRevisionDocuments);
                    Assert.Equal(14, stats.CountOfAttachments);
                    Assert.Equal(4, stats.CountOfUniqueAttachments);
                }

                using (var store2 = GetDocumentStore(new Options
                {
                    ModifyDatabaseName = s => $"{s}_store2"
                }))
                {
                    var dbId = new Guid("00000000-48c4-421e-9466-000000000000");
                    await SetDatabaseId(store2, dbId);

                    await RevisionsHelper.SetupRevisions(Server.ServerStore, store2.Database);

                    for (var i = 0; i < 2; i++) // Make sure that we can import attachments twice and it will overwrite
                    {
                        await store2.Smuggler.ImportAsync(new DatabaseSmugglerImportOptions(), file);

                        var stats = await store2.Admin.SendAsync(new GetStatisticsOperation());

                        Assert.Equal(1, stats.CountOfDocuments);
                        Assert.Equal(5, stats.CountOfRevisionDocuments);
                        Assert.Equal(14, stats.CountOfAttachments);
                        Assert.Equal(4, stats.CountOfUniqueAttachments);

                        using (var session = store2.OpenSession())
                        {
                            var readBuffer = new byte[1024 * 1024];
                            using (var attachmentStream = new MemoryStream(readBuffer))
                                using (var attachment = session.Advanced.GetAttachment("users/1", "big-file"))
                                {
                                    attachment.Stream.CopyTo(attachmentStream);
                                    Assert.Contains("A:" + (2 + 20 * i), attachment.Details.ChangeVector);
                                    Assert.Equal("big-file", attachment.Details.Name);
                                    Assert.Equal("zKHiLyLNRBZti9DYbzuqZ/EDWAFMgOXB+SwKvjPAINk=", attachment.Details.Hash);
                                    Assert.Equal(999 * 1024, attachmentStream.Position);
                                    Assert.Equal(Enumerable.Range(1, 999 * 1024).Select(x => (byte)x), readBuffer.Take((int)attachmentStream.Position));
                                }
                        }
                    }
                }
            }
            finally
            {
                File.Delete(file);
            }
        }
        public async Task ExportEmptyStream()
        {
            var file = Path.GetTempFileName();

            try
            {
                var dbId2 = new Guid("99999999-48c4-421e-9466-999999999999");
                var dbId  = new Guid("00000000-48c4-421e-9466-000000000000");

                using (var store1 = GetDocumentStore(new Options
                {
                    ModifyDatabaseName = s => $"{s}_store1"
                }))
                {
                    await SetDatabaseId(store1, dbId);

                    await RevisionsHelper.SetupRevisions(Server.ServerStore, store1.Database, false, 4);

                    using (var session = store1.OpenSession())
                    {
                        session.Store(new User {
                            Name = "Fitzchak"
                        }, "users/1");
                        session.SaveChanges();
                    }
                    using (var emptyStream = new MemoryStream(new byte[0]))
                    {
                        var result = store1.Operations.Send(new PutAttachmentOperation("users/1", "empty-file", emptyStream, "image/png"));
                        Assert.Equal("A:3", result.ChangeVector.Substring(0, 3));
                        Assert.Equal("empty-file", result.Name);
                        Assert.Equal("users/1", result.DocumentId);
                        Assert.Equal("image/png", result.ContentType);
                        Assert.Equal("DldRwCblQ7Loqy6wYJnaodHl30d3j3eH+qtFzfEv46g=", result.Hash);
                        Assert.Equal(0, result.Size);
                    }

                    await store1.Smuggler.ExportAsync(new DatabaseSmugglerExportOptions(), file);

                    var stats = await store1.Admin.SendAsync(new GetStatisticsOperation());

                    Assert.Equal(1, stats.CountOfDocuments);
                    Assert.Equal(2, stats.CountOfRevisionDocuments);
                    Assert.Equal(2, stats.CountOfAttachments);
                    Assert.Equal(1, stats.CountOfUniqueAttachments);
                }

                using (var store2 = GetDocumentStore(new Options
                {
                    ModifyDatabaseName = s => $"{s}_store2"
                }))
                {
                    await SetDatabaseId(store2, dbId2);

                    await RevisionsHelper.SetupRevisions(Server.ServerStore, store2.Database);

                    await store2.Smuggler.ImportAsync(new DatabaseSmugglerImportOptions(), file);

                    var stats = await store2.Admin.SendAsync(new GetStatisticsOperation());

                    Assert.Equal(1, stats.CountOfDocuments);
                    Assert.Equal(3, stats.CountOfRevisionDocuments);
                    Assert.Equal(2, stats.CountOfAttachments);
                    Assert.Equal(1, stats.CountOfUniqueAttachments);

                    using (var session = store2.OpenSession())
                    {
                        var readBuffer = new byte[1024 * 1024];
                        using (var attachmentStream = new MemoryStream(readBuffer))
                            using (var attachment = session.Advanced.GetAttachment("users/1", "empty-file"))
                            {
                                attachment.Stream.CopyTo(attachmentStream);
                                Assert.Contains("A:1", attachment.Details.ChangeVector);
                                Assert.Equal("empty-file", attachment.Details.Name);
                                Assert.Equal(0, attachment.Details.Size);
                                Assert.Equal("DldRwCblQ7Loqy6wYJnaodHl30d3j3eH+qtFzfEv46g=", attachment.Details.Hash);
                                Assert.Equal(0, attachmentStream.Position);
                                Assert.Equal(new byte[0], readBuffer.Take((int)attachmentStream.Position));
                            }
                    }
                }
            }
            finally
            {
                File.Delete(file);
            }
        }
        public async Task RevertResolvedConflictByLocalToDeleted()
        {
            // deleted was at 8:50
            // conflict at 9:10
            // resolved at 9:15
            // will revert to 9:00

            using (var store1 = GetDocumentStore())
                using (var store2 = GetDocumentStore())
                {
                    await RevisionsHelper.SetupRevisions(Server.ServerStore, store1.Database);

                    DateTime last = default;

                    using (var session = store2.OpenAsyncSession())
                    {
                        var company = new Person
                        {
                            Name = "Name2"
                        };
                        await session.StoreAsync(company, "foo/bar");

                        await session.SaveChangesAsync();


                        await session.StoreAsync(new Company(), "marker");

                        await session.SaveChangesAsync();
                    }

                    using (var session = store1.OpenAsyncSession())
                    {
                        var company = new Person
                        {
                            Name = "Name1"
                        };
                        await session.StoreAsync(company, "foo/bar");

                        await session.SaveChangesAsync();

                        session.Delete("foo/bar");
                        await session.SaveChangesAsync();

                        var companiesRevisions = await session.Advanced.Revisions.GetForAsync <Person>("foo/bar");

                        Assert.Equal(2, companiesRevisions.Count);

                        last = DateTime.UtcNow;
                    }

                    await SetupReplicationAsync(store2, store1);

                    WaitForDocument(store1, "marker");

                    using (var session = store1.OpenAsyncSession())
                    {
                        var companiesRevisions = await session.Advanced.Revisions.GetForAsync <Person>("foo/bar");

                        Assert.Equal(4, companiesRevisions.Count);
                    }

                    var db = await GetDocumentDatabaseInstanceFor(store1);

                    RevertResult result;
                    using (var token = new OperationCancelToken(db.Configuration.Databases.OperationTimeout.AsTimeSpan, db.DatabaseShutdown))
                    {
                        result = (RevertResult)await db.DocumentsStorage.RevisionsStorage.RevertRevisions(last, TimeSpan.FromMinutes(60), onProgress : null,
                                                                                                          token : token);
                    }

                    Assert.Equal(5, result.ScannedRevisions);
                    Assert.Equal(2, result.ScannedDocuments);
                    Assert.Equal(1, result.RevertedDocuments);

                    using (var session = store1.OpenAsyncSession())
                    {
                        var persons = await session.Advanced.Revisions.GetForAsync <Person>("foo/bar");

                        Assert.Equal(5, persons.Count);

                        Assert.Equal(null, persons[0].Name);
                        var metadata = session.Advanced.GetMetadataFor(persons[0]);
                        Assert.Equal((DocumentFlags.HasRevisions | DocumentFlags.DeleteRevision | DocumentFlags.Reverted).ToString(), metadata.GetString(Constants.Documents.Metadata.Flags));

                        Assert.Equal(null, persons[1].Name);
                        metadata = session.Advanced.GetMetadataFor(persons[1]);
                        Assert.Equal((DocumentFlags.HasRevisions | DocumentFlags.DeleteRevision | DocumentFlags.Resolved).ToString(), metadata.GetString(Constants.Documents.Metadata.Flags));

                        Assert.Equal(null, persons[2].Name);
                        metadata = session.Advanced.GetMetadataFor(persons[2]);
                        Assert.Equal((DocumentFlags.HasRevisions | DocumentFlags.DeleteRevision | DocumentFlags.Conflicted).ToString(), metadata.GetString(Constants.Documents.Metadata.Flags));

                        Assert.Equal("Name2", persons[3].Name);
                        metadata = session.Advanced.GetMetadataFor(persons[3]);
                        Assert.Equal((DocumentFlags.HasRevisions | DocumentFlags.Revision | DocumentFlags.FromReplication | DocumentFlags.Conflicted).ToString(), metadata.GetString(Constants.Documents.Metadata.Flags));

                        Assert.Equal("Name1", persons[4].Name);
                        metadata = session.Advanced.GetMetadataFor(persons[4]);
                        Assert.Equal((DocumentFlags.HasRevisions | DocumentFlags.Revision).ToString(), metadata.GetString(Constants.Documents.Metadata.Flags));
                    }
                }
        }
        public async Task ClusterTransactionRequestWithRevisions()
        {
            var leader = await CreateRaftClusterAndGetLeader(5, shouldRunInMemory : false, leaderIndex : 0);

            using (var leaderStore = GetDocumentStore(new Options
            {
                DeleteDatabaseOnDispose = false,
                Server = leader,
                ReplicationFactor = 5,
                ModifyDocumentStore = (store) => store.Conventions.DisableTopologyUpdates = true
            }))
            {
                var user1 = new User()
                {
                    Name = "Karmel"
                };
                var user3 = new User()
                {
                    Name = "Indych"
                };
                var index = await RevisionsHelper.SetupRevisions(leader.ServerStore, leaderStore.Database, configuration => configuration.Collections["Users"].PurgeOnDelete = false);
                await WaitForRaftIndexToBeAppliedInCluster(index, TimeSpan.FromSeconds(15));

                // bring our SUT node down, but we still have a cluster and can execute cluster transaction.
                var server  = Servers[1];
                var url     = server.WebUrl;
                var dataDir = Servers[1].Configuration.Core.DataDirectory.FullPath.Split('/').Last();

                await DisposeServerAndWaitForFinishOfDisposalAsync(server);

                using (var session = leaderStore.OpenAsyncSession(new SessionOptions
                {
                    TransactionMode = TransactionMode.ClusterWide
                }))
                {
                    Assert.Equal(1, session.Advanced.RequestExecutor.TopologyNodes.Count);
                    Assert.Equal(leader.WebUrl, session.Advanced.RequestExecutor.Url);
                    session.Advanced.ClusterTransaction.CreateCompareExchangeValue("usernames/ayende", user1);
                    await session.StoreAsync(user3, "foo/bar");

                    await session.SaveChangesAsync();

                    var user = (await session.Advanced.ClusterTransaction.GetCompareExchangeValueAsync <User>("usernames/ayende")).Value;
                    Assert.Equal(user1.Name, user.Name);
                    user = await session.LoadAsync <User>("foo/bar");

                    Assert.Equal(user3.Name, user.Name);

                    var list = await session.Advanced.Revisions.GetForAsync <User>(user.Id);

                    Assert.Equal(1, list.Count);
                    var changeVector = session.Advanced.GetChangeVectorFor(user);
                    Assert.NotNull(await session.Advanced.Revisions.GetAsync <User>(changeVector));
                }
                // bring more nodes down, so only one node is left
                var dataDir2 = Servers[2].Configuration.Core.DataDirectory.FullPath.Split('/').Last();
                var url2     = Servers[2].WebUrl;
                var task1    = DisposeServerAndWaitForFinishOfDisposalAsync(Servers[2]);
                var task2    = DisposeServerAndWaitForFinishOfDisposalAsync(Servers[3]);
                var task3    = DisposeServerAndWaitForFinishOfDisposalAsync(Servers[4]);
                await Task.WhenAll(task1, task2, task3);

                using (var session = leaderStore.OpenAsyncSession())
                {
                    Assert.Equal(leader.WebUrl, session.Advanced.RequestExecutor.Url);
                    await session.StoreAsync(user1, "foo/bar");

                    await session.SaveChangesAsync();

                    var list = await session.Advanced.Revisions.GetForAsync <User>(user1.Id);

                    Assert.Equal(2, list.Count);
                }

                long lastRaftIndex;
                using (leader.ServerStore.Engine.ContextPool.AllocateOperationContext(out TransactionOperationContext ctx))
                    using (ctx.OpenReadTransaction())
                    {
                        lastRaftIndex = leader.ServerStore.Engine.GetLastCommitIndex(ctx);
                    }

                // revive the SUT node
                var revived = Servers[1] = GetNewServer(new Dictionary <string, string>
                {
                    [RavenConfiguration.GetKey(x => x.Core.ServerUrls)]         = url,
                    [RavenConfiguration.GetKey(x => x.Cluster.ElectionTimeout)] = "400"
                }, runInMemory: false, deletePrevious: false, partialPath: dataDir);
                using (var revivedStore = new DocumentStore()
                {
                    Urls = new[] { revived.WebUrl },
                    Database = leaderStore.Database,
                    Conventions = new DocumentConventions
                    {
                        DisableTopologyUpdates = true
                    }
                }.Initialize())
                {
                    // let the document with the revision to replicate
                    Assert.True(WaitForDocument(revivedStore, "foo/bar"));
                    using (var session = revivedStore.OpenAsyncSession())
                    {
                        var user = await session.LoadAsync <User>("foo/bar");

                        var changeVector = session.Advanced.GetChangeVectorFor(user);
                        Assert.NotNull(await session.Advanced.Revisions.GetAsync <User>(changeVector));
                        var list = await session.Advanced.Revisions.GetForAsync <User>("foo/bar");

                        Assert.Equal(2, list.Count);

                        // revive another node so we should have a functional cluster now
                        Servers[2] = GetNewServer(new Dictionary <string, string>
                        {
                            [RavenConfiguration.GetKey(x => x.Core.ServerUrls)]         = url2,
                            [RavenConfiguration.GetKey(x => x.Cluster.ElectionTimeout)] = "400"
                        }, runInMemory: false, deletePrevious: false, partialPath: dataDir2);

                        // wait for the log to apply on the SUT node
                        using (var cts = new CancellationTokenSource(TimeSpan.FromSeconds(15)))
                        {
                            await leader.ServerStore.Engine.WaitForLeaveState(RachisState.Candidate, cts.Token);
                        }
                        var database = await Servers[1].ServerStore.DatabasesLandlord.TryGetOrCreateResourceStore(leaderStore.Database);
                        await database.RachisLogIndexNotifications.WaitForIndexNotification(lastRaftIndex, TimeSpan.FromSeconds(15));

                        list = await session.Advanced.Revisions.GetForAsync <User>("foo/bar");

                        Assert.Equal(2, list.Count);
                    }
                }
            }
        }
Exemple #16
0
        public async Task CanGetTimeSeriesSnapshotInRevisions()
        {
            using (var store = GetDocumentStore())
            {
                await RevisionsHelper.SetupRevisions(Server.ServerStore, store.Database);

                using (var session = store.OpenAsyncSession())
                {
                    // revision 1
                    await session.StoreAsync(new Company(), "companies/1-A");

                    await session.SaveChangesAsync();
                }

                var baseline = DateTime.Today;

                using (var session = store.OpenAsyncSession())
                {
                    var company = await session.LoadAsync <Company>("companies/1-A");

                    // revision 2
                    company.Name = "HR";
                    await session.SaveChangesAsync();

                    var tsf = session.TimeSeriesFor(company, "temperature");

                    // revision 3
                    tsf.Append(baseline.AddMinutes(10), 17.5);
                    tsf.Append(baseline.AddMinutes(20), 17.4);

                    await session.SaveChangesAsync();

                    // no revision for this one
                    tsf.Append(baseline.AddMinutes(30), new[] { 17.2d });

                    await session.SaveChangesAsync();
                }

                using (var session = store.OpenAsyncSession())
                {
                    var companiesRevisions = await session.Advanced.Revisions.GetForAsync <Company>("companies/1-A");

                    Assert.Equal(3, companiesRevisions.Count);
                    var metadatas = companiesRevisions.Select(c => session.Advanced.GetMetadataFor(c)).ToList();

                    Assert.Equal("HR", companiesRevisions[0].Name);

                    var tsRevisions = (IMetadataDictionary)metadatas[0][Constants.Documents.Metadata.RevisionTimeSeries];
                    Assert.Equal(1, tsRevisions.Count);

                    var tsStats = (IMetadataDictionary)tsRevisions["temperature"];
                    Assert.Equal(2L, tsStats["Count"]);
                    Assert.Equal(baseline.AddMinutes(10), DateTime.Parse((string)tsStats["Start"]), RavenTestHelper.DateTimeComparer.Instance);
                    Assert.Equal(baseline.AddMinutes(20), DateTime.Parse((string)tsStats["End"]), RavenTestHelper.DateTimeComparer.Instance);

                    Assert.Equal("HR", companiesRevisions[1].Name);
                    Assert.False(metadatas[1].TryGetValue(Constants.Documents.Metadata.RevisionTimeSeries, out _));

                    Assert.Null(companiesRevisions[2].Name);
                    Assert.False(metadatas[1].TryGetValue(Constants.Documents.Metadata.RevisionTimeSeries, out _));
                }

                using (var session = store.OpenAsyncSession())
                {
                    var company = await session.LoadAsync <Company>("companies/1-A");

                    // revision 4
                    company.Name = "Hibernating Rhinos";
                    await session.SaveChangesAsync();

                    // revision 5
                    var tsf = session.TimeSeriesFor(company, "temperature");
                    tsf.Append(baseline.AddMonths(6), new[] { 27.6d }); // will create a new segment

                    tsf = session.TimeSeriesFor(company, "heartrate");
                    tsf.Append(baseline.AddHours(1), new[] { 92.8d });
                    tsf.Append(baseline.AddHours(2), new[] { 89d });

                    await session.SaveChangesAsync();
                }

                using (var session = store.OpenAsyncSession())
                {
                    var companiesRevisions = await session.Advanced.Revisions.GetForAsync <Company>("companies/1-A");

                    Assert.Equal(5, companiesRevisions.Count);
                    var metadatas = companiesRevisions.Select(c => session.Advanced.GetMetadataFor(c)).ToList();

                    Assert.Equal("Hibernating Rhinos", companiesRevisions[0].Name);
                    var tsRevisions = (IMetadataDictionary)metadatas[0][Constants.Documents.Metadata.RevisionTimeSeries];
                    Assert.Equal(2, tsRevisions.Count);

                    var tsStats = (IMetadataDictionary)tsRevisions["temperature"];
                    Assert.Equal(4L, tsStats["Count"]);
                    Assert.Equal(baseline.AddMinutes(10), DateTime.Parse((string)tsStats["Start"]), RavenTestHelper.DateTimeComparer.Instance);
                    Assert.Equal(baseline.AddMonths(6), DateTime.Parse((string)tsStats["End"]), RavenTestHelper.DateTimeComparer.Instance);

                    tsStats = (IMetadataDictionary)tsRevisions["heartrate"];
                    Assert.Equal(2L, tsStats["Count"]);
                    Assert.Equal(baseline.AddHours(1), DateTime.Parse((string)tsStats["Start"]), RavenTestHelper.DateTimeComparer.Instance);
                    Assert.Equal(baseline.AddHours(2), DateTime.Parse((string)tsStats["End"]), RavenTestHelper.DateTimeComparer.Instance);

                    Assert.Equal("Hibernating Rhinos", companiesRevisions[1].Name);
                    tsRevisions = (IMetadataDictionary)metadatas[1][Constants.Documents.Metadata.RevisionTimeSeries];
                    Assert.Equal(1, tsRevisions.Count);
                    tsStats = (IMetadataDictionary)tsRevisions["temperature"];

                    Assert.Equal(3L, tsStats["Count"]);
                    Assert.Equal(baseline.AddMinutes(10), DateTime.Parse((string)tsStats["Start"]), RavenTestHelper.DateTimeComparer.Instance);
                    Assert.Equal(baseline.AddMinutes(30), DateTime.Parse((string)tsStats["End"]), RavenTestHelper.DateTimeComparer.Instance);

                    Assert.Equal("HR", companiesRevisions[2].Name);
                    tsRevisions = (IMetadataDictionary)metadatas[2][Constants.Documents.Metadata.RevisionTimeSeries];
                    Assert.Equal(1, tsRevisions.Count);
                    tsStats = (IMetadataDictionary)tsRevisions["temperature"];

                    Assert.Equal(2L, tsStats["Count"]);
                    Assert.Equal(baseline.AddMinutes(10), DateTime.Parse((string)tsStats["Start"]), RavenTestHelper.DateTimeComparer.Instance);
                    Assert.Equal(baseline.AddMinutes(20), DateTime.Parse((string)tsStats["End"]), RavenTestHelper.DateTimeComparer.Instance);

                    Assert.Equal("HR", companiesRevisions[3].Name);
                    Assert.False(metadatas[3].TryGetValue(Constants.Documents.Metadata.RevisionCounters, out _));

                    Assert.Null(companiesRevisions[4].Name);
                    Assert.False(metadatas[4].TryGetValue(Constants.Documents.Metadata.RevisionCounters, out _));
                }
            }
        }
Exemple #17
0
        public async Task CanIncrementNumberOfRequests()
        {
            using (var store = GetDocumentStore())
            {
                const string id = "users/Hibernating";

                await RevisionsHelper.SetupRevisions(Server.ServerStore, store.Database);

                using (var session = store.OpenAsyncSession())
                {
                    await session.StoreAsync(new User
                    {
                        Name = "Hibernating",
                    }, id);

                    byte[] byteArray = Encoding.UTF8.GetBytes("Rhinos");

                    await session.SaveChangesAsync();

                    session.Advanced.Attachments.Store(id,
                                                       "invoice.pdf",
                                                       new MemoryStream(byteArray),
                                                       "application/pdf");

                    await session.SaveChangesAsync();
                }

                string changeVector;
                using (var session = store.OpenAsyncSession())
                {
                    var metadatas = await session.Advanced.Revisions.GetMetadataForAsync(id);

                    Assert.Equal(2, metadatas.Count);

                    changeVector = metadatas.First().GetString(Constants.Documents.Metadata.ChangeVector);
                }

                using (var session = store.OpenAsyncSession())
                {
                    var revision1 = await session.Advanced.Revisions.GetAsync <User>(id, DateTime.UtcNow);

                    var revision2 = await session.Advanced.Revisions.GetAsync <User>(changeVector : changeVector);

                    var revision3 = await session.Advanced.Revisions.GetAsync <User>(new[] { changeVector });

                    Assert.NotNull(revision1);
                    Assert.NotNull(revision2);
                    Assert.NotNull(revision3);

                    using (var attachment = await session.Advanced.Attachments.GetAsync(id, "invoice.pdf"))
                    {
                        Assert.NotNull(attachment);
                    }

                    Assert.Equal(4, session.Advanced.NumberOfRequests);
                }

                using (var session = store.OpenSession())
                {
                    var revision1 = session.Advanced.Revisions.Get <User>(id, DateTime.UtcNow);
                    var revision2 = session.Advanced.Revisions.Get <User>(changeVector: changeVector);
                    var revision3 = session.Advanced.Revisions.Get <User>(new[] { changeVector });

                    Assert.NotNull(revision1);
                    Assert.NotNull(revision2);
                    Assert.NotNull(revision3);

                    Assert.Equal(3, session.Advanced.NumberOfRequests);
                }
            }
        }
Exemple #18
0
        public async Task RealSupportForTransactionMarkerAcrossMultiUpdates()
        {
            using (var store1 = GetDocumentStore())
                using (var store2 = GetDocumentStore())
                {
                    var database1 = await GetDocumentDatabaseInstanceFor(store1);

                    database1.Configuration.Replication.MaxItemsCount          = 1;
                    database1.ReplicationLoader.DebugWaitAndRunReplicationOnce = new ManualResetEventSlim();

                    await RevisionsHelper.SetupRevisions(Server.ServerStore, store1.Database, configuration =>
                    {
                        configuration.Collections["Users"].PurgeOnDelete = false;
                    });

                    await RevisionsHelper.SetupRevisions(Server.ServerStore, store2.Database, configuration =>
                    {
                        configuration.Collections["Users"].PurgeOnDelete = false;
                    });

                    using (var session = store1.OpenAsyncSession())
                    {
                        await session.StoreAsync(new User { Id = "users/oren", Name = "Oren", Balance = 10 });

                        await session.StoreAsync(new User { Id = "users/fitzchak", Name = "Fitzchak", Balance = 10 });

                        await session.StoreAsync(new User { Id = "users/michael", Name = "Michael", Balance = 10 });

                        await session.SaveChangesAsync();
                    }

                    using (var session = store1.OpenAsyncSession())
                    {
                        var fitzchak = await session.LoadAsync <User>("users/fitzchak");

                        var michael = await session.LoadAsync <User>("users/michael");

                        michael.Balance  -= 10;
                        fitzchak.Balance += 10;
                        await session.SaveChangesAsync();
                    }

                    using (var session = store1.OpenAsyncSession())
                    {
                        var fitzchak = await session.LoadAsync <User>("users/fitzchak");

                        var oren = await session.LoadAsync <User>("users/oren");

                        fitzchak.Balance -= 5;
                        oren.Balance     += 5;
                        await session.SaveChangesAsync();
                    }

                    using (var session = store1.OpenAsyncSession())
                    {
                        var michael = await session.LoadAsync <User>("users/michael");

                        session.Delete(michael);
                        var fitzchak = await session.LoadAsync <User>("users/fitzchak");

                        var oren = await session.LoadAsync <User>("users/oren");

                        fitzchak.Balance -= 5;
                        oren.Balance     += 5;
                        await session.SaveChangesAsync();
                    }


                    using (var session = store1.OpenAsyncSession())
                    {
                        await session.StoreAsync(new User { Id = "users/michael", Name = "Michael", Balance = 10 });

                        var oren = await session.LoadAsync <User>("users/oren");

                        oren.Balance -= 10;
                        await session.SaveChangesAsync();
                    }

                    await SetupReplicationAsync(store1, store2);

                    database1.ReplicationLoader.DebugWaitAndRunReplicationOnce.Set();
                    using (var session = store2.OpenAsyncSession())
                    {
                        Assert.True(WaitForDocument <User>(store2, "users/michael", u => u.Balance == 10));
                        var fitzchak = await session.LoadAsync <User>("users/fitzchak");

                        var oren = await session.LoadAsync <User>("users/oren");

                        Assert.Equal(10, fitzchak.Balance);
                        Assert.Equal(10, oren.Balance);
                    }

                    database1.ReplicationLoader.DebugWaitAndRunReplicationOnce.Set();
                    using (var session = store2.OpenAsyncSession())
                    {
                        Assert.True(WaitForDocument <User>(store2, "users/michael", u => u.Balance == 0));
                        var fitzchak = await session.LoadAsync <User>("users/fitzchak");

                        var oren = await session.LoadAsync <User>("users/oren");

                        Assert.Equal(20, fitzchak.Balance);
                        Assert.Equal(10, oren.Balance);
                    }

                    database1.ReplicationLoader.DebugWaitAndRunReplicationOnce.Set();
                    using (var session = store2.OpenAsyncSession())
                    {
                        Assert.True(WaitForDocument <User>(store2, "users/oren", u => u.Balance == 15));
                        var fitzchak = await session.LoadAsync <User>("users/fitzchak");

                        var michael = await session.LoadAsync <User>("users/michael");

                        Assert.Equal(15, fitzchak.Balance);
                        Assert.Equal(0, michael.Balance);
                    }

                    database1.ReplicationLoader.DebugWaitAndRunReplicationOnce.Set();
                    using (var session = store2.OpenAsyncSession())
                    {
                        Assert.True(WaitForDocument <User>(store2, "users/oren", u => u.Balance == 20));
                        var fitzchak = await session.LoadAsync <User>("users/fitzchak");

                        var michael = await session.LoadAsync <User>("users/michael");

                        Assert.Equal(10, fitzchak.Balance);
                        Assert.Null(michael);
                    }

                    database1.ReplicationLoader.DebugWaitAndRunReplicationOnce.Set();
                    using (var session = store2.OpenAsyncSession())
                    {
                        Assert.True(WaitForDocument <User>(store2, "users/oren", u => u.Balance == 10));
                        var fitzchak = await session.LoadAsync <User>("users/fitzchak");

                        var michael = await session.LoadAsync <User>("users/michael");

                        Assert.Equal(10, fitzchak.Balance);
                        Assert.Equal(10, michael.Balance);
                    }
                }
        }
        public async Task ExportEmptyStream()
        {
            var file = GetTempFileName();

            try
            {
                var          dbId2          = new Guid("99999999-48c4-421e-9466-999999999999");
                var          dbId           = new Guid("00000000-48c4-421e-9466-000000000000");
                const string documentId     = "users/1";
                const string attachmentName = "empty-file";

                using (var store1 = GetDocumentStore(new Options
                {
                    ModifyDatabaseName = s => $"{s}_store1"
                }))
                {
                    await SetDatabaseId(store1, dbId);

                    await RevisionsHelper.SetupRevisions(Server.ServerStore, store1.Database, configuration =>
                    {
                        configuration.Collections["Users"].PurgeOnDelete          = false;
                        configuration.Collections["Users"].MinimumRevisionsToKeep = 4;
                    });

                    using (var session = store1.OpenSession())
                    {
                        session.Store(new User {
                            Name = "Fitzchak"
                        }, documentId);
                        session.SaveChanges();
                    }

                    using (var emptyStream = new MemoryStream(new byte[0]))
                    {
                        var result = store1.Operations.Send(new PutAttachmentOperation(documentId, attachmentName, emptyStream, "image/png"));
                        Assert.Equal("A:3", result.ChangeVector.Substring(0, 3));
                        Assert.Equal(attachmentName, result.Name);
                        Assert.Equal(documentId, result.DocumentId);
                        Assert.Equal("image/png", result.ContentType);
                        Assert.Equal("DldRwCblQ7Loqy6wYJnaodHl30d3j3eH+qtFzfEv46g=", result.Hash);
                        Assert.Equal(0, result.Size);
                    }

                    var exportOperation = await store1.Smuggler.ExportAsync(new DatabaseSmugglerExportOptions(), file);

                    var exportResult = (SmugglerResult)exportOperation.WaitForCompletion();

                    Assert.Equal(1, exportResult.Documents.ReadCount);
                    Assert.Equal(2, exportResult.RevisionDocuments.ReadCount);
                    Assert.Equal(1, exportResult.Documents.Attachments.ReadCount);
                    Assert.Equal(1, exportResult.RevisionDocuments.Attachments.ReadCount);

                    var stats = await store1.Maintenance.SendAsync(new GetStatisticsOperation());

                    Assert.Equal(1, stats.CountOfDocuments);
                    Assert.Equal(2, stats.CountOfRevisionDocuments);
                    Assert.Equal(2, stats.CountOfAttachments);
                    Assert.Equal(1, stats.CountOfUniqueAttachments);
                }

                using (var store2 = GetDocumentStore(new Options
                {
                    ModifyDatabaseName = s => $"{s}_store2"
                }))
                {
                    await SetDatabaseId(store2, dbId2);

                    var importOperation = await store2.Smuggler.ImportAsync(new DatabaseSmugglerImportOptions(), file);

                    var importResult = (SmugglerResult)importOperation.WaitForCompletion();

                    Assert.Equal(1, importResult.Documents.ReadCount);
                    Assert.Equal(2, importResult.RevisionDocuments.ReadCount);
                    Assert.Equal(1, importResult.Documents.Attachments.ReadCount);
                    Assert.Equal(1, importResult.RevisionDocuments.Attachments.ReadCount);

                    var stats = await store2.Maintenance.SendAsync(new GetStatisticsOperation());

                    Assert.Equal(1, stats.CountOfDocuments);
                    Assert.Equal(3, stats.CountOfRevisionDocuments);
                    Assert.Equal(2 + 1, stats.CountOfAttachments); // the imported document will create 1 additional revision with 1 attachment
                    Assert.Equal(1, stats.CountOfUniqueAttachments);

                    using (var session = store2.OpenSession())
                    {
                        var readBuffer = new byte[1024 * 1024];
                        using (var attachmentStream = new MemoryStream(readBuffer))
                            using (var attachment = session.Advanced.Attachments.Get(documentId, attachmentName))
                            {
                                attachment.Stream.CopyTo(attachmentStream);
                                Assert.Equal(new byte[0], readBuffer.Take((int)attachmentStream.Position));

                                var attachmentCv = attachment.Details.ChangeVector;
                                Assert.Contains("A:1", attachmentCv);
                                Assert.Equal(attachmentName, attachment.Details.Name);
                                Assert.Equal(0, attachment.Details.Size);
                                Assert.Equal("DldRwCblQ7Loqy6wYJnaodHl30d3j3eH+qtFzfEv46g=", attachment.Details.Hash);
                                Assert.Equal(0, attachmentStream.Position);

                                var user           = session.Load <User>(documentId);
                                var documentCv     = session.Advanced.GetChangeVectorFor(user);
                                var conflictStatus = ChangeVectorUtils.GetConflictStatus(documentCv, attachmentCv);
                                // document CV is larger than attachment CV
                                Assert.Equal(ConflictStatus.Update, conflictStatus);
                            }
                    }
                }
            }
            finally
            {
                File.Delete(file);
            }
        }
Exemple #20
0
        public async Task RevertRevisionWithDeleteAttachments()
        {
            var names = new[]
            {
                "background-photo.jpg",
                "fileNAME_#$1^%_בעברית.txt",
                "profile.png",
            };
            DateTime last = default;

            using (var store = GetDocumentStore())
            {
                await RevisionsHelper.SetupRevisions(Server.ServerStore, store.Database);

                using (var session = store.OpenAsyncSession())
                {
                    await session.StoreAsync(new User { Name = "Name1", LastName = "LastName1" }, "users/1");

                    await using (var backgroundStream = new MemoryStream(new byte[] { 10, 20, 30, 40, 50 }))
                    {
                        session.Advanced.Attachments.Store("users/1", names[0], backgroundStream, "ImGgE/jPeG");
                        await session.SaveChangesAsync();
                    }
                    last = DateTime.UtcNow;
                }

                using (var session = store.OpenAsyncSession())
                {
                    session.Advanced.Attachments.Delete("users/1", names[0]);
                    await session.SaveChangesAsync();
                }

                var db = await Databases.GetDocumentDatabaseInstanceFor(store);

                RevertResult result;
                using (var token = new OperationCancelToken(db.Configuration.Databases.OperationTimeout.AsTimeSpan, db.DatabaseShutdown, CancellationToken.None))
                {
                    result = (RevertResult)await db.DocumentsStorage.RevisionsStorage.RevertRevisions(last, TimeSpan.FromMinutes(60), onProgress : null,
                                                                                                      token : token);
                }
                WaitForUserToContinueTheTest(store);
                using (var session = store.OpenAsyncSession())
                {
                    var rev = await session.Advanced.Revisions.GetForAsync <User>("users/1");

                    Assert.Equal(4, rev.Count);
                    var cv = session.Advanced.GetChangeVectorFor(rev[0]);
                    Assert.Equal("Name1", rev[0].Name);
                    Assert.NotNull(await session.Advanced.Attachments.GetRevisionAsync("users/1", names[0], cv));

                    var user = await session.LoadAsync <User>("users/1");

                    var metadata = session.Advanced.GetMetadataFor(user);
                    var flags    = metadata.GetString(Constants.Documents.Metadata.Flags);
                    Assert.Contains(DocumentFlags.HasAttachments.ToString(), flags);
                    var att = session.Advanced.Attachments.GetNames(user);
                    Assert.Equal(1, att.Length);
                    Assert.Equal(names[0], att[0].Name);
                }
            }
        }
Exemple #21
0
        public async Task limitRevisionDeletionWithEnforceConfiguration()
        {
            using (var store = GetDocumentStore())
            {
                var configuration = new RevisionsConfiguration
                {
                    Default = new RevisionsCollectionConfiguration
                    {
                        Disabled = false,
                        MinimumRevisionsToKeep = 1000000
                    },
                };
                await RevisionsHelper.SetupRevisions(store, Server.ServerStore, configuration);

                using (var session = store.OpenAsyncSession())
                {
                    await session.StoreAsync(new User { Name = "Toli" }, "users/1");

                    await session.StoreAsync(new User { Name = "Mitzi" }, "users/2");

                    await session.StoreAsync(new Order { Employee = "Daniel" }, "orders/1");

                    await session.SaveChangesAsync();
                }

                for (int i = 0; i < 500; i++)
                {
                    using (var session = store.OpenAsyncSession())
                    {
                        await session.StoreAsync(new User { Name = "Toli" + i }, "users/1");

                        await session.StoreAsync(new User { Name = "Mitzi" + i }, "users/2");

                        await session.StoreAsync(new Order { Employee = "Daniel" + i }, "orders/1");

                        await session.SaveChangesAsync();
                    }
                }
                for (int i = 500; i < 630; i++)
                {
                    using (var session = store.OpenAsyncSession())
                    {
                        await session.StoreAsync(new User { Name = "Mitzi" + i }, "users/2");

                        await session.SaveChangesAsync();
                    }
                }
                using (var session = store.OpenAsyncSession())
                {
                    var revisionCount = session.Advanced.Revisions.GetForAsync <User>("users/1", 0, 1000).Result.Count;
                    Assert.Equal(501, revisionCount);
                    revisionCount = session.Advanced.Revisions.GetForAsync <User>("users/2", 0, 1000).Result.Count;
                    Assert.Equal(631, revisionCount);
                    revisionCount = session.Advanced.Revisions.GetForAsync <User>("orders/1", 0, 1000).Result.Count;
                    Assert.Equal(501, revisionCount);
                }

                configuration = new RevisionsConfiguration
                {
                    Default = new RevisionsCollectionConfiguration
                    {
                        Disabled = false,
                        MinimumRevisionsToKeep = 10,
                        MaximumRevisionsToDeleteUponDocumentUpdate = 100
                    },
                    Collections = new Dictionary <string, RevisionsCollectionConfiguration>
                    {
                        ["Orders"] = new RevisionsCollectionConfiguration
                        {
                            Disabled = false,
                            MinimumRevisionsToKeep = 33,
                            MaximumRevisionsToDeleteUponDocumentUpdate = 35
                        }
                    }
                };
                await RevisionsHelper.SetupRevisions(store, Server.ServerStore, configuration);

                var db = await Databases.GetDocumentDatabaseInstanceFor(store);

                using (var token = new OperationCancelToken(db.Configuration.Databases.OperationTimeout.AsTimeSpan, db.DatabaseShutdown, CancellationToken.None))
                    await db.DocumentsStorage.RevisionsStorage.EnforceConfiguration(_ => { }, token);
                WaitForUserToContinueTheTest(store);
                using (var session = store.OpenAsyncSession())
                {
                    var revisionCount = session.Advanced.Revisions.GetForAsync <User>("users/1", 0, 100).Result.Count;
                    Assert.Equal(10, revisionCount);
                    revisionCount = session.Advanced.Revisions.GetForAsync <User>("users/2", 0, 100).Result.Count;
                    Assert.Equal(10, revisionCount);
                    revisionCount = session.Advanced.Revisions.GetForAsync <Order>("orders/1", 0, 100).Result.Count;
                    Assert.Equal(33, revisionCount);
                }
            }
        }
Exemple #22
0
        public async Task RemoveRevertFlagAfterNewInfo1()
        {
            using (var store = GetDocumentStore())
            {
                await RevisionsHelper.SetupRevisions(Server.ServerStore, store.Database);

                DateTime last = default;

                using (var session = store.OpenAsyncSession())
                {
                    var person = new Person
                    {
                        Name = "Name1"
                    };
                    await session.StoreAsync(person, "foo/bar");

                    await session.SaveChangesAsync();

                    last = DateTime.UtcNow;
                }

                using (var session = store.OpenAsyncSession())
                {
                    var person = new Person
                    {
                        Name = "Name2"
                    };
                    await session.StoreAsync(person, "foo/bar");

                    await session.SaveChangesAsync();
                }

                var db = await Databases.GetDocumentDatabaseInstanceFor(store);

                RevertResult result;
                using (var token = new OperationCancelToken(db.Configuration.Databases.OperationTimeout.AsTimeSpan, db.DatabaseShutdown, CancellationToken.None))
                {
                    result = (RevertResult)await db.DocumentsStorage.RevisionsStorage.RevertRevisions(last, TimeSpan.FromMinutes(60), onProgress : null,
                                                                                                      token : token);
                }

                Assert.Equal(2, result.ScannedRevisions);
                Assert.Equal(1, result.ScannedDocuments);
                Assert.Equal(1, result.RevertedDocuments);

                using (var session = store.OpenAsyncSession())
                {
                    var persons = await session.Advanced.Revisions.GetForAsync <Person>("foo/bar");

                    Assert.Equal(3, persons.Count);

                    Assert.Equal("Name1", persons[0].Name);
                    var metadata = session.Advanced.GetMetadataFor(persons[0]);
                    Assert.Equal((DocumentFlags.HasRevisions | DocumentFlags.Revision | DocumentFlags.Reverted).ToString(), metadata.GetString(Constants.Documents.Metadata.Flags));

                    await using (var backgroundStream = new MemoryStream(new byte[] { 10, 20, 30, 40, 50 }))
                    {
                        session.Advanced.Attachments.Store("foo/bar", "background-photo.jpg", backgroundStream, "ImGgE/jPeG");
                        await session.SaveChangesAsync();
                    }
                }
                using (var session = store.OpenAsyncSession())
                {
                    var foo = await session.LoadAsync <Person>("foo/bar");

                    var metadata = session.Advanced.GetMetadataFor(foo);
                    var flags    = metadata.GetString(Constants.Documents.Metadata.Flags);
                    Assert.False(flags.Contains(DocumentFlags.Reverted.ToString()));

                    var persons = await session.Advanced.Revisions.GetForAsync <Person>("foo/bar");

                    Assert.Equal(4, persons.Count);

                    Assert.Equal("Name1", persons[0].Name);
                    metadata = session.Advanced.GetMetadataFor(persons[0]);
                    Assert.Equal((DocumentFlags.HasRevisions | DocumentFlags.Revision | DocumentFlags.HasAttachments).ToString(), metadata.GetString(Constants.Documents.Metadata.Flags));
                }
            }
        }
        public async Task CanExportAndImportWithRevisionDocumentsFromCollection()
        {
            var file = GetTempFileName();

            try
            {
                using (var store1 = GetDocumentStore(new Options
                {
                    ModifyDatabaseName = s => $"{s}_store1"
                }))
                {
                    using (var session = store1.OpenAsyncSession())
                    {
                        await RevisionsHelper.SetupRevisions(Server.ServerStore, store1.Database);

                        await session.StoreAsync(new Person { Name = "Name1" });

                        await session.StoreAsync(new Person { Name = "Name2" });

                        await session.StoreAsync(new Company { Name = "Hibernating Rhinos " });

                        await session.SaveChangesAsync();
                    }

                    for (int i = 0; i < 2; i++)
                    {
                        using (var session = store1.OpenAsyncSession())
                        {
                            var company = await session.LoadAsync <Company>("companies/1-A");

                            var person = await session.LoadAsync <Person>("people/1-A");

                            company.Name += " update " + i;
                            person.Name  += " update " + i;
                            await session.StoreAsync(company);

                            await session.StoreAsync(person);

                            await session.SaveChangesAsync();
                        }
                    }

                    var operation = await store1.Smuggler.ExportAsync(new DatabaseSmugglerExportOptions
                    {
                        Collections = new List <string>()
                        {
                            "Companies"
                        }
                    }, file);

                    await operation.WaitForCompletionAsync(TimeSpan.FromMinutes(1));

                    var stats = await store1.Maintenance.SendAsync(new GetStatisticsOperation());

                    Assert.Equal(5, stats.CountOfDocuments);
                    Assert.Equal(7, stats.CountOfRevisionDocuments);
                }

                using (var store2 = GetDocumentStore(new Options
                {
                    ModifyDatabaseName = s => $"{s}_store2"
                }))
                {
                    var operation = await store2.Smuggler.ImportAsync(new DatabaseSmugglerImportOptions()
                    {
                        SkipRevisionCreation = true
                    }, file);

                    await operation.WaitForCompletionAsync(TimeSpan.FromMinutes(1));

                    WaitForUserToContinueTheTest(store2);
                    var stats = await store2.Maintenance.SendAsync(new GetStatisticsOperation());

                    Assert.Equal(1, stats.CountOfDocuments);
                    Assert.Equal(3, stats.CountOfRevisionDocuments);
                }
            }
            finally
            {
                File.Delete(file);
            }
        }
Exemple #24
0
        public async Task RevertToTombstone()
        {
            using (var store = GetDocumentStore())
            {
                await RevisionsHelper.SetupRevisions(Server.ServerStore, store.Database);

                DateTime last = default;

                using (var session = store.OpenAsyncSession())
                {
                    var person = new Person
                    {
                        Name = "Name1"
                    };
                    await session.StoreAsync(person, "foo/bar");

                    session.CountersFor("foo/bar").Increment("Downloads", 100);
                    await session.SaveChangesAsync();
                }

                using (var session = store.OpenAsyncSession())
                {
                    session.Delete("foo/bar");
                    await session.SaveChangesAsync();

                    last = DateTime.UtcNow;
                }

                using (var session = store.OpenAsyncSession())
                {
                    var person = new Person
                    {
                        Name = "Name2"
                    };
                    await session.StoreAsync(person, "foo/bar");

                    await session.SaveChangesAsync();
                }
                var db = await Databases.GetDocumentDatabaseInstanceFor(store);

                RevertResult result;
                using (var token = new OperationCancelToken(db.Configuration.Databases.OperationTimeout.AsTimeSpan, db.DatabaseShutdown, CancellationToken.None))
                {
                    result = (RevertResult)await db.DocumentsStorage.RevisionsStorage.RevertRevisions(last, TimeSpan.FromMinutes(60), onProgress : null,
                                                                                                      token : token);
                }

                Assert.Equal(4, result.ScannedRevisions);
                Assert.Equal(1, result.ScannedDocuments);
                Assert.Equal(1, result.RevertedDocuments);

                using (var session = store.OpenAsyncSession())
                {
                    var foo = await session.LoadAsync <User>("foo/bar");

                    Assert.Null(foo);
                    var persons = await session.Advanced.Revisions.GetForAsync <Person>("foo/bar");

                    Assert.Equal(5, persons.Count);

                    var metadata = session.Advanced.GetMetadataFor(persons[0]);
                    Assert.Equal((DocumentFlags.HasRevisions | DocumentFlags.DeleteRevision | DocumentFlags.Reverted).ToString(), metadata.GetString(Constants.Documents.Metadata.Flags));
                }

                using (var session = store.OpenAsyncSession())
                {
                    var person = new Person
                    {
                        Name = "Name1"
                    };
                    await session.StoreAsync(person, "foo/bar");

                    await session.SaveChangesAsync();
                }

                using (var session = store.OpenAsyncSession())
                {
                    var foo = await session.LoadAsync <User>("foo/bar");

                    var metadata = session.Advanced.GetMetadataFor(foo);
                    var flags    = metadata.GetString(Constants.Documents.Metadata.Flags);
                    Assert.DoesNotContain(DocumentFlags.HasCounters.ToString(), flags);
                }
            }
        }
        public async Task ShouldAvoidCreatingNewRevisionsDuringImport()
        {
            var file = GetTempFileName();

            try
            {
                using (var store1 = GetDocumentStore(new Options
                {
                    ModifyDatabaseName = s => $"{s}_store1"
                }))
                {
                    using (var session = store1.OpenAsyncSession())
                    {
                        await RevisionsHelper.SetupRevisions(Server.ServerStore, store1.Database);

                        await session.StoreAsync(new Person { Name = "Name1" });

                        await session.StoreAsync(new Person { Name = "Name2" });

                        await session.StoreAsync(new Company { Name = "Hibernating Rhinos " });

                        await session.SaveChangesAsync();
                    }

                    for (int i = 0; i < 2; i++)
                    {
                        using (var session = store1.OpenAsyncSession())
                        {
                            var company = await session.LoadAsync <Company>("companies/1-A");

                            var person = await session.LoadAsync <Person>("people/1-A");

                            company.Name += " update " + i;
                            person.Name  += " update " + i;
                            await session.StoreAsync(company);

                            await session.StoreAsync(person);

                            await session.SaveChangesAsync();
                        }
                    }

                    using (var session = store1.OpenAsyncSession())
                    {
                        var person = await session.LoadAsync <Person>("people/2-A");

                        Assert.NotNull(person);
                        session.Delete(person);
                        await session.SaveChangesAsync();
                    }

                    var operation = await store1.Smuggler.ExportAsync(new DatabaseSmugglerExportOptions(), file);

                    await operation.WaitForCompletionAsync(TimeSpan.FromMinutes(1));

                    var stats = await store1.Maintenance.SendAsync(new GetStatisticsOperation());

                    Assert.Equal(4, stats.CountOfDocuments);
                    Assert.Equal(8, stats.CountOfRevisionDocuments);
                }

                using (var store2 = GetDocumentStore(new Options
                {
                    ModifyDatabaseName = s => $"{s}_store2"
                }))
                {
                    var operation = await store2.Smuggler.ImportAsync(new DatabaseSmugglerImportOptions
                    {
                        SkipRevisionCreation = true
                    }, file);

                    await operation.WaitForCompletionAsync(TimeSpan.FromMinutes(1));

                    var stats = await store2.Maintenance.SendAsync(new GetStatisticsOperation());

                    Assert.Equal(4, stats.CountOfDocuments);
                    Assert.Equal(8, stats.CountOfRevisionDocuments);
                }
            }
            finally
            {
                File.Delete(file);
            }
        }
Exemple #26
0
        public async Task RevertRevisionWithTimeSeries()
        {
            DateTime last = default;

            using (var store = GetDocumentStore())
            {
                await RevisionsHelper.SetupRevisions(Server.ServerStore, store.Database);

                using (var session = store.OpenAsyncSession())
                {
                    await session.StoreAsync(new User { Name = "Name1", LastName = "LastName1" }, "users/1");

                    var ts = session.TimeSeriesFor("users/1", "Toli");
                    ts.Append(DateTime.Today.AddDays(-1), 10);
                    await session.SaveChangesAsync();

                    last = DateTime.UtcNow;
                }

                using (var session = store.OpenAsyncSession())
                {
                    await session.StoreAsync(new User { Name = "Name2", LastName = "LastName1" }, "users/1");

                    var ts = session.TimeSeriesFor("users/1", "Mitzi");
                    ts.Append(DateTime.Today, 30);
                    await session.SaveChangesAsync();
                }

                var db = await Databases.GetDocumentDatabaseInstanceFor(store);

                RevertResult result;
                using (var token = new OperationCancelToken(db.Configuration.Databases.OperationTimeout.AsTimeSpan, db.DatabaseShutdown, CancellationToken.None))
                {
                    result = (RevertResult)await db.DocumentsStorage.RevisionsStorage.RevertRevisions(last, TimeSpan.FromMinutes(60), onProgress : null,
                                                                                                      token : token);
                }

                using (var session = store.OpenAsyncSession())
                {
                    var rev = await session.Advanced.Revisions.GetForAsync <User>("users/1");

                    Assert.Equal(5, rev.Count);

                    Assert.Equal("Name1", rev[0].Name);
                    var ts = await session.TimeSeriesFor(rev[0], "Toli").GetAsync();

                    Assert.Equal(1, ts.Length);
                    Assert.Equal(10, ts[0].Value);

                    ts = await session.TimeSeriesFor(rev[0], "Mitzi").GetAsync();

                    Assert.Equal(1, ts.Length);
                    Assert.Equal(30, ts[0].Value);

                    var user = await session.LoadAsync <User>("users/1");

                    Assert.Equal("Name1", user.Name);
                    var metadata = session.Advanced.GetMetadataFor(user);
                    Assert.True(metadata.Keys.Contains(Constants.Documents.Metadata.TimeSeries));
                    Assert.False(metadata.Keys.Contains(Constants.Documents.Metadata.RevisionTimeSeries));
                    var flags = metadata.GetString(Constants.Documents.Metadata.Flags);
                    Assert.Contains(DocumentFlags.HasTimeSeries.ToString(), flags);
                    ts = await session.TimeSeriesFor(user, "Toli").GetAsync();

                    Assert.Equal(1, ts.Length);
                    Assert.Equal(10, ts[0].Value);
                    ts = await session.TimeSeriesFor(user, "Mitzi").GetAsync();

                    Assert.Equal(1, ts.Length);
                    Assert.Equal(30, ts[0].Value);
                }
            }
        }
        public async Task ReplicateExpiredRevisions()
        {
            var revisionsAgeLimit = TimeSpan.FromSeconds(10);

            Action <RevisionsConfiguration> modifyConfiguration = configuration =>
                                                                  configuration.Collections["Users"] = new RevisionsCollectionConfiguration
            {
                Disabled = false,
                MinimumRevisionAgeToKeep = revisionsAgeLimit
            };

            using (var store1 = GetDocumentStore())
                using (var store2 = GetDocumentStore())
                {
                    await RevisionsHelper.SetupRevisions(Server.ServerStore, store1.Database, modifyConfiguration);

                    await RevisionsHelper.SetupRevisions(Server.ServerStore, store2.Database, modifyConfiguration);

                    using (var session = store1.OpenAsyncSession())
                    {
                        await session.StoreAsync(new User
                        {
                            Name = "Aviv"
                        }, "users/1-A");

                        await session.SaveChangesAsync();
                    }

                    for (int i = 2; i <= 10; i++)
                    {
                        using (var session = store1.OpenAsyncSession())
                        {
                            var user = await session.LoadAsync <User>("users/1-A");

                            user.Name = "Aviv" + i;
                            await session.SaveChangesAsync();
                        }
                    }

                    using (var session = store1.OpenAsyncSession())
                    {
                        var revisions = await session.Advanced.Revisions.GetForAsync <User>("users/1-A");

                        Assert.Equal(10, revisions.Count);
                    }


                    // wait until revisions are expired
                    await Task.Delay(revisionsAgeLimit);

                    // setup replication
                    await SetupReplicationAsync(store1, store2);

                    WaitForMarker(store1, store2);

                    // store1 should still have 10 revisions
                    // store2 should have no revisions
                    using (var session = store1.OpenAsyncSession())
                    {
                        var revisions = await session.Advanced.Revisions.GetForAsync <User>("users/1-A");

                        Assert.Equal(10, revisions.Count);
                    }
                    using (var session = store2.OpenAsyncSession())
                    {
                        var revisions = await session.Advanced.Revisions.GetForAsync <User>("users/1-A");

                        Assert.Equal(0, revisions.Count);
                    }

                    /*
                     *              // TODO : RavenDB-13359
                     *              using (var session = store2.OpenAsyncSession())
                     *              {
                     *                  var doc = await session.LoadAsync<User>("users/1-A");
                     *                  var md = session.Advanced.GetMetadataFor(doc);
                     *                  md.TryGetValue(Constants.Documents.Metadata.Flags, out var flags);
                     *
                     *                  Assert.DoesNotContain(nameof(DocumentFlags.HasRevisions), flags);
                     *              }
                     */

                    // modify doc on store1 to create another revision
                    using (var session = store1.OpenAsyncSession())
                    {
                        var user = await session.LoadAsync <User>("users/1-A");

                        user.Name = "Grisha";
                        await session.SaveChangesAsync();
                    }

                    WaitForMarker(store1, store2);

                    // assert that both stores have just one revision
                    using (var session = store1.OpenAsyncSession())
                    {
                        var revisions = await session.Advanced.Revisions.GetForAsync <User>("users/1-A");

                        Assert.Equal(1, revisions.Count);
                        Assert.Equal("Grisha", revisions[0].Name);
                    }
                    using (var session = store2.OpenAsyncSession())
                    {
                        var revisions = await session.Advanced.Revisions.GetForAsync <User>("users/1-A");

                        Assert.Equal(1, revisions.Count);
                        Assert.Equal("Grisha", revisions[0].Name);
                    }
                }
        }
Exemple #28
0
        public async Task RemoveResolveFlagAfterRevert()
        {
            using (var store1 = GetDocumentStore())
                using (var store2 = GetDocumentStore())
                {
                    await RevisionsHelper.SetupRevisions(Server.ServerStore, store1.Database);

                    DateTime last = default;

                    using (var session = store1.OpenAsyncSession())
                    {
                        var person = new Person
                        {
                            Name = "Name1"
                        };
                        await session.StoreAsync(person, "foo/bar");

                        await session.SaveChangesAsync();
                    }

                    using (var session = store2.OpenAsyncSession())
                    {
                        var person = new Person
                        {
                            Name = "Name2"
                        };
                        await session.StoreAsync(person, "foo/bar");

                        await session.SaveChangesAsync();


                        await session.StoreAsync(new Person(), "marker");

                        await session.SaveChangesAsync();
                    }

                    await SetupReplicationAsync(store2, store1);

                    WaitForDocument(store1, "marker");

                    last = DateTime.UtcNow;
                    using (var session = store1.OpenAsyncSession())
                    {
                        var person = new Person
                        {
                            Name = "Name3"
                        };
                        await session.StoreAsync(person, "foo/bar");

                        await session.SaveChangesAsync();
                    }
                    var db = await Databases.GetDocumentDatabaseInstanceFor(store1);

                    WaitForUserToContinueTheTest(store1);
                    RevertResult result;
                    using (var token = new OperationCancelToken(db.Configuration.Databases.OperationTimeout.AsTimeSpan, db.DatabaseShutdown, CancellationToken.None))
                    {
                        result = (RevertResult)await db.DocumentsStorage.RevisionsStorage.RevertRevisions(last, TimeSpan.FromMinutes(60), onProgress : null,
                                                                                                          token : token);
                    }

                    Assert.Equal(5, result.ScannedRevisions);
                    Assert.Equal(2, result.ScannedDocuments);
                    Assert.Equal(1, result.RevertedDocuments);

                    using (var session = store1.OpenAsyncSession())
                    {
                        var foo = await session.LoadAsync <User>("foo/bar");

                        var metadata = session.Advanced.GetMetadataFor(foo);
                        var flags    = metadata.GetString(Constants.Documents.Metadata.Flags);
                        Assert.Contains(DocumentFlags.Reverted.ToString(), flags);
                        Assert.False(flags.Contains(DocumentFlags.Resolved.ToString()));

                        var persons = await session.Advanced.Revisions.GetForAsync <Person>("foo/bar");

                        Assert.Equal(5, persons.Count);

                        Assert.Equal("Name2", persons[0].Name);
                        metadata = session.Advanced.GetMetadataFor(persons[0]);
                        Assert.Equal((DocumentFlags.HasRevisions | DocumentFlags.Revision | DocumentFlags.Reverted).ToString(), metadata.GetString(Constants.Documents.Metadata.Flags));

                        Assert.Equal("Name3", persons[1].Name);
                        metadata = session.Advanced.GetMetadataFor(persons[1]);
                        Assert.Equal((DocumentFlags.HasRevisions | DocumentFlags.Revision).ToString(), metadata.GetString(Constants.Documents.Metadata.Flags));

                        Assert.Equal("Name2", persons[2].Name);
                        metadata = session.Advanced.GetMetadataFor(persons[2]);
                        Assert.Equal((DocumentFlags.HasRevisions | DocumentFlags.Revision | DocumentFlags.Resolved).ToString(), metadata.GetString(Constants.Documents.Metadata.Flags));
                    }
                }
        }
        public async Task ReplicateRevisionTombstones()
        {
            var revisionsAgeLimit = TimeSpan.FromSeconds(10);

            Action <RevisionsConfiguration> modifyConfiguration = configuration =>
                                                                  configuration.Collections["Users"] = new RevisionsCollectionConfiguration
            {
                Disabled = false,
                MinimumRevisionAgeToKeep = revisionsAgeLimit
            };

            using (var store1 = GetDocumentStore())
                using (var store2 = GetDocumentStore())
                {
                    //setup revisions on both stores and setup replication
                    await RevisionsHelper.SetupRevisions(Server.ServerStore, store1.Database, modifyConfiguration);

                    await RevisionsHelper.SetupRevisions(Server.ServerStore, store2.Database, modifyConfiguration);

                    await SetupReplicationAsync(store1, store2);

                    // create some revisions on store1
                    using (var session = store1.OpenAsyncSession())
                    {
                        await session.StoreAsync(new User
                        {
                            Name = "Aviv"
                        }, "users/1-A");

                        await session.SaveChangesAsync();
                    }

                    for (int i = 2; i <= 10; i++)
                    {
                        using (var session = store1.OpenAsyncSession())
                        {
                            var user = await session.LoadAsync <User>("users/1-A");

                            user.Name = "Aviv" + i;
                            await session.SaveChangesAsync();
                        }
                    }

                    // wait for replication
                    WaitForMarker(store1, store2);

                    // wait until revisions are expired
                    await Task.Delay(revisionsAgeLimit);

                    // modify document
                    using (var session = store1.OpenAsyncSession())
                    {
                        var user = await session.LoadAsync <User>("users/1-A");

                        user.Name = "Grisha";
                        await session.SaveChangesAsync();
                    }

                    WaitForMarker(store1, store2);

                    // expired revisions should be deleted
                    // assert that both stores have 10 revision tombstones

                    foreach (var store in new[] { store1, store2 })
                    {
                        var documentDatabase = await GetDocumentDatabaseInstanceFor(store);

                        using (documentDatabase.DocumentsStorage.ContextPool.AllocateOperationContext(out DocumentsOperationContext ctx))
                            using (ctx.OpenReadTransaction())
                            {
                                var tombstones = documentDatabase.DocumentsStorage.GetTombstonesFrom(ctx, 0, 0, int.MaxValue).ToList();
                                Assert.Equal(10, tombstones.Count);

                                foreach (var tombstone in tombstones)
                                {
                                    Assert.Equal(Tombstone.TombstoneType.Revision, tombstone.Type);
                                }
                            }
                    }
                }
        }
        public async Task RevertRevisionOutsideTheWindow()
        {
            var company = new Company {
                Name = "Company Name"
            };

            using (var store = GetDocumentStore())
            {
                await RevisionsHelper.SetupRevisions(Server.ServerStore, store.Database);

                using (var session = store.OpenAsyncSession())
                {
                    await session.StoreAsync(company);

                    await session.SaveChangesAsync();
                }

                await Task.Delay(2000);

                using (var session = store.OpenAsyncSession())
                {
                    company.Name = "Hibernating Rhinos";
                    await session.StoreAsync(company);

                    await session.SaveChangesAsync();
                }

                await Task.Delay(5000);

                DateTime last = DateTime.UtcNow;
                last = last.AddSeconds(-3);

                using (var session = store.OpenAsyncSession())
                {
                    company.Name = "Hibernating Rhinos 2";
                    await session.StoreAsync(company);

                    await session.SaveChangesAsync();
                }

                await Task.Delay(2000);

                var db = await GetDocumentDatabaseInstanceFor(store);

                RevertResult result;
                using (var token = new OperationCancelToken(db.Configuration.Databases.OperationTimeout.AsTimeSpan, db.DatabaseShutdown))
                {
                    result = (RevertResult)await db.DocumentsStorage.RevisionsStorage.RevertRevisions(last, TimeSpan.FromSeconds(1), onProgress : null,
                                                                                                      token : token);
                }

                Assert.Equal(3, result.ScannedRevisions);
                Assert.Equal(1, result.ScannedDocuments);
                Assert.Equal(1, result.RevertedDocuments);

                using (var session = store.OpenAsyncSession())
                {
                    var companiesRevisions = await session.Advanced.Revisions.GetForAsync <Company>(company.Id);

                    Assert.Equal(4, companiesRevisions.Count);

                    Assert.Equal("Hibernating Rhinos", companiesRevisions[0].Name);
                    Assert.Equal("Hibernating Rhinos 2", companiesRevisions[1].Name);
                    Assert.Equal("Hibernating Rhinos", companiesRevisions[2].Name);
                    Assert.Equal("Company Name", companiesRevisions[3].Name);
                }
            }
        }