Example #1
0
            [InlineData(4, 8, 15, 0)] // 4,        8 + 4 = 12 is greater than 10 so 8 is the batch size.
            public async Task RespectsAzureSearchBatchSize(int documentsPerId, int batchSize, int fullPushes, int partialPushes)
            {
                var changeCount    = 30;
                var expectedPushes = fullPushes + partialPushes;

                Config.AzureSearchBatchSize = 10;

                IndexActions = new IndexActions(
                    new List <IndexAction <KeyedDocument> >(
                        Enumerable
                        .Range(0, documentsPerId)
                        .Select(x => IndexAction.Merge(new KeyedDocument()))),
                    new List <IndexAction <KeyedDocument> >(),
                    new ResultAndAccessCondition <VersionListData>(
                        new VersionListData(new Dictionary <string, VersionPropertiesData>()),
                        new Mock <IAccessCondition>().Object));

                AddChanges(changeCount);

                await Target.ExecuteAsync();

                VerifyCompletedTelemetry(JobOutcome.Success);
                VerifyAllIdsAreProcessed(changeCount);
                IndexActionBuilder.Verify(
                    x => x.UpdateAsync(
                        It.IsAny <string>(),
                        It.IsAny <Func <SearchFilters, KeyedDocument> >()),
                    Times.Exactly(changeCount));
                BatchPusher.Verify(
                    x => x.EnqueueIndexActions(It.IsAny <string>(), It.IsAny <IndexActions>()),
                    Times.Exactly(changeCount));
                BatchPusher.Verify(x => x.TryFinishAsync(), Times.Exactly(expectedPushes));
                BatchPusher.Verify(x => x.TryPushFullBatchesAsync(), Times.Never);
                SystemTime.Verify(x => x.Delay(It.IsAny <TimeSpan>()), Times.Exactly(expectedPushes - 1));
                DownloadDataClient.Verify(
                    x => x.ReplaceLatestIndexedAsync(
                        NewDownloadData,
                        It.Is <IAccessCondition>(a => a.IfMatchETag == OldDownloadResult.Metadata.ETag)),
                    Times.Once);

                Assert.Equal(
                    fullPushes,
                    FinishedBatches.Count(b => b.Sum(ia => ia.Search.Count) == batchSize));
                Assert.Equal(
                    partialPushes,
                    FinishedBatches.Count(b => b.Sum(ia => ia.Search.Count) != batchSize));
                Assert.Empty(CurrentBatch);
            }
Example #2
0
        public DocumentDatabase(InMemoryRavenConfiguration configuration, TransportState transportState = null)
        {
            DocumentLock        = new PutSerialLock();
            Name                = configuration.DatabaseName;
            Configuration       = configuration;
            this.transportState = transportState ?? new TransportState();
            ExtensionsState     = new AtomicDictionary <object>();

            using (LogManager.OpenMappedContext("database", Name ?? Constants.SystemDatabase))
            {
                Log.Debug("Start loading the following database: {0}", Name ?? Constants.SystemDatabase);

                initializer = new DocumentDatabaseInitializer(this, configuration);

                initializer.InitializeEncryption();
                initializer.ValidateLicense();

                initializer.SubscribeToDomainUnloadOrProcessExit();
                initializer.ExecuteAlterConfiguration();
                initializer.SatisfyImportsOnce();

                backgroundTaskScheduler = configuration.CustomTaskScheduler ?? TaskScheduler.Default;


                recentTouches = new SizeLimitedConcurrentDictionary <string, TouchedDocumentInfo>(configuration.MaxRecentTouchesToRemember, StringComparer.OrdinalIgnoreCase);

                configuration.Container.SatisfyImportsOnce(this);

                workContext = new WorkContext
                {
                    Database            = this,
                    DatabaseName        = Name,
                    IndexUpdateTriggers = IndexUpdateTriggers,
                    ReadTriggers        = ReadTriggers,
                    TaskScheduler       = backgroundTaskScheduler,
                    Configuration       = configuration,
                    IndexReaderWarmers  = IndexReaderWarmers
                };

                try
                {
                    uuidGenerator = new SequentialUuidGenerator();
                    initializer.InitializeTransactionalStorage(uuidGenerator);
                    lastCollectionEtags = new LastCollectionEtags(TransactionalStorage, WorkContext);
                }
                catch (Exception)
                {
                    if (TransactionalStorage != null)
                    {
                        TransactionalStorage.Dispose();
                    }
                    throw;
                }

                try
                {
                    TransactionalStorage.Batch(actions => uuidGenerator.EtagBase = actions.General.GetNextIdentityValue("Raven/Etag"));

                    // Index codecs must be initialized before we try to read an index
                    InitializeIndexCodecTriggers();
                    initializer.InitializeIndexStorage();

                    Attachments   = new AttachmentActions(this, recentTouches, uuidGenerator, Log);
                    Documents     = new DocumentActions(this, recentTouches, uuidGenerator, Log);
                    Indexes       = new IndexActions(this, recentTouches, uuidGenerator, Log);
                    Maintenance   = new MaintenanceActions(this, recentTouches, uuidGenerator, Log);
                    Notifications = new NotificationActions(this, recentTouches, uuidGenerator, Log);
                    Patches       = new PatchActions(this, recentTouches, uuidGenerator, Log);
                    Queries       = new QueryActions(this, recentTouches, uuidGenerator, Log);
                    Tasks         = new TaskActions(this, recentTouches, uuidGenerator, Log);
                    Transformers  = new TransformerActions(this, recentTouches, uuidGenerator, Log);

                    inFlightTransactionalState = TransactionalStorage.GetInFlightTransactionalState(Documents.Put, Documents.Delete);

                    CompleteWorkContextSetup();

                    prefetcher       = new Prefetcher(workContext);
                    indexingExecuter = new IndexingExecuter(workContext, prefetcher);

                    RaiseIndexingWiringComplete();

                    InitializeTriggersExceptIndexCodecs();
                    SecondStageInitialization();
                    ExecuteStartupTasks();
                    lastCollectionEtags.Initialize();

                    Log.Debug("Finish loading the following database: {0}", configuration.DatabaseName ?? Constants.SystemDatabase);
                }
                catch (Exception)
                {
                    Dispose();
                    throw;
                }
            }
        }
            public Facts(ITestOutputHelper output)
            {
                DatabaseOwnerFetcher     = new Mock <IDatabaseAuxiliaryDataFetcher>();
                OwnerDataClient          = new Mock <IOwnerDataClient>();
                OwnerSetComparer         = new Mock <IDataSetComparer>();
                SearchDocumentBuilder    = new Mock <ISearchDocumentBuilder>();
                SearchIndexActionBuilder = new Mock <ISearchIndexActionBuilder>();
                Pusher           = new Mock <IBatchPusher>();
                Options          = new Mock <IOptionsSnapshot <AzureSearchJobConfiguration> >();
                TelemetryService = new Mock <IAzureSearchTelemetryService>();
                Logger           = output.GetLogger <UpdateOwnersCommand>();

                Configuration = new AzureSearchJobConfiguration
                {
                    MaxConcurrentBatches = 1,
                };
                DatabaseResult = new SortedDictionary <string, SortedSet <string> >();
                StorageResult  = new ResultAndAccessCondition <SortedDictionary <string, SortedSet <string> > >(
                    new SortedDictionary <string, SortedSet <string> >(),
                    new Mock <IAccessCondition>().Object);
                Changes      = new SortedDictionary <string, string[]>();
                IndexActions = new IndexActions(
                    new List <IndexAction <KeyedDocument> > {
                    IndexAction.Merge(new KeyedDocument())
                },
                    new List <IndexAction <KeyedDocument> > {
                    IndexAction.Merge(new KeyedDocument())
                },
                    new ResultAndAccessCondition <VersionListData>(
                        new VersionListData(new Dictionary <string, VersionPropertiesData>()),
                        new Mock <IAccessCondition>().Object));

                Pusher.SetReturnsDefault(Task.FromResult(new BatchPusherResult()));
                Options
                .Setup(x => x.Value)
                .Returns(() => Configuration);
                DatabaseOwnerFetcher
                .Setup(x => x.GetPackageIdToOwnersAsync())
                .ReturnsAsync(() => DatabaseResult);
                OwnerDataClient
                .Setup(x => x.ReadLatestIndexedAsync())
                .ReturnsAsync(() => StorageResult);
                OwnerSetComparer
                .Setup(x => x.CompareOwners(
                           It.IsAny <SortedDictionary <string, SortedSet <string> > >(),
                           It.IsAny <SortedDictionary <string, SortedSet <string> > >()))
                .Returns(() => Changes);
                SearchIndexActionBuilder
                .Setup(x => x.UpdateAsync(It.IsAny <string>(), It.IsAny <Func <SearchFilters, KeyedDocument> >()))
                .ReturnsAsync(() => IndexActions);

                Target = new UpdateOwnersCommand(
                    DatabaseOwnerFetcher.Object,
                    OwnerDataClient.Object,
                    OwnerSetComparer.Object,
                    SearchDocumentBuilder.Object,
                    SearchIndexActionBuilder.Object,
                    () => Pusher.Object,
                    Options.Object,
                    TelemetryService.Object,
                    Logger);
            }
Example #4
0
            public Facts(ITestOutputHelper output)
            {
                AuxiliaryFileClient          = new Mock <IAuxiliaryFileClient>();
                DatabaseFetcher              = new Mock <IDatabaseAuxiliaryDataFetcher>();
                DownloadDataClient           = new Mock <IDownloadDataClient>();
                DownloadSetComparer          = new Mock <IDownloadSetComparer>();
                DownloadTransferrer          = new Mock <IDownloadTransferrer>();
                PopularityTransferDataClient = new Mock <IPopularityTransferDataClient>();
                SearchDocumentBuilder        = new Mock <ISearchDocumentBuilder>();
                IndexActionBuilder           = new Mock <ISearchIndexActionBuilder>();
                BatchPusher      = new Mock <IBatchPusher>();
                SystemTime       = new Mock <ISystemTime>();
                FeatureFlags     = new Mock <IFeatureFlagService>();
                Options          = new Mock <IOptionsSnapshot <Auxiliary2AzureSearchConfiguration> >();
                TelemetryService = new Mock <IAzureSearchTelemetryService>();
                Logger           = output.GetLogger <Auxiliary2AzureSearchCommand>();

                Config = new Auxiliary2AzureSearchConfiguration
                {
                    AzureSearchBatchSize            = 10,
                    MaxConcurrentBatches            = 1,
                    MaxConcurrentVersionListWriters = 1,
                    EnablePopularityTransfers       = true,
                    MinPushPeriod = TimeSpan.FromSeconds(5),
                };
                Options.Setup(x => x.Value).Returns(() => Config);

                OldDownloadData   = new DownloadData();
                OldDownloadResult = Data.GetAuxiliaryFileResult(OldDownloadData, "download-data-etag");
                DownloadDataClient
                .Setup(x => x.ReadLatestIndexedAsync(It.IsAny <IAccessCondition>(), It.IsAny <StringCache>()))
                .ReturnsAsync(() => OldDownloadResult);
                NewDownloadData = new DownloadData();
                AuxiliaryFileClient.Setup(x => x.LoadDownloadDataAsync()).ReturnsAsync(() => NewDownloadData);

                Changes = new SortedDictionary <string, long>();
                DownloadSetComparer
                .Setup(x => x.Compare(It.IsAny <DownloadData>(), It.IsAny <DownloadData>()))
                .Returns(() => Changes);

                OldTransfers      = new PopularityTransferData();
                OldTransferResult = new AuxiliaryFileResult <PopularityTransferData>(
                    modified: true,
                    data: OldTransfers,
                    metadata: new AuxiliaryFileMetadata(
                        DateTimeOffset.UtcNow,
                        TimeSpan.Zero,
                        fileSize: 0,
                        etag: "etag"));
                PopularityTransferDataClient
                .Setup(x => x.ReadLatestIndexedAsync(It.IsAny <IAccessCondition>(), It.IsAny <StringCache>()))
                .ReturnsAsync(OldTransferResult);

                NewTransfers = new PopularityTransferData();
                DatabaseFetcher
                .Setup(x => x.GetPopularityTransfersAsync())
                .ReturnsAsync(NewTransfers);

                TransferChanges = new SortedDictionary <string, long>(StringComparer.OrdinalIgnoreCase);
                DownloadTransferrer
                .Setup(x => x.UpdateDownloadTransfers(
                           It.IsAny <DownloadData>(),
                           It.IsAny <SortedDictionary <string, long> >(),
                           It.IsAny <PopularityTransferData>(),
                           It.IsAny <PopularityTransferData>()))
                .Returns(TransferChanges);

                IndexActions = new IndexActions(
                    new List <IndexAction <KeyedDocument> > {
                    IndexAction.Merge(new KeyedDocument())
                },
                    new List <IndexAction <KeyedDocument> >(),
                    new ResultAndAccessCondition <VersionListData>(
                        new VersionListData(new Dictionary <string, VersionPropertiesData>()),
                        Mock.Of <IAccessCondition>()));
                ProcessedIds = new ConcurrentBag <string>();
                IndexActionBuilder
                .Setup(x => x.UpdateAsync(It.IsAny <string>(), It.IsAny <Func <SearchFilters, KeyedDocument> >()))
                .ReturnsAsync(() => IndexActions)
                .Callback <string, Func <SearchFilters, KeyedDocument> >((id, b) =>
                {
                    ProcessedIds.Add(id);
                    b(SearchFilters.IncludePrereleaseAndSemVer2);
                });

                // When pushing, delay for a little bit of time so the stopwatch has some measurable duration.
                PushedIds       = new ConcurrentBag <string>();
                CurrentBatch    = new ConcurrentBag <IndexActions>();
                FinishedBatches = new ConcurrentBag <List <IndexActions> >();
                BatchPusher
                .Setup(x => x.EnqueueIndexActions(It.IsAny <string>(), It.IsAny <IndexActions>()))
                .Callback <string, IndexActions>((id, indexActions) =>
                {
                    CurrentBatch.Add(indexActions);
                    PushedIds.Add(id);
                });
                BatchPusher
                .Setup(x => x.TryFinishAsync())
                .Returns(async() =>
                {
                    await Task.Delay(TimeSpan.FromMilliseconds(1));
                    return(new BatchPusherResult());
                })
                .Callback(() =>
                {
                    FinishedBatches.Add(CurrentBatch.ToList());
                    CurrentBatch = new ConcurrentBag <IndexActions>();
                });

                FeatureFlags.Setup(x => x.IsPopularityTransferEnabled()).Returns(true);

                Target = new UpdateDownloadsCommand(
                    AuxiliaryFileClient.Object,
                    DatabaseFetcher.Object,
                    DownloadDataClient.Object,
                    DownloadSetComparer.Object,
                    DownloadTransferrer.Object,
                    PopularityTransferDataClient.Object,
                    SearchDocumentBuilder.Object,
                    IndexActionBuilder.Object,
                    () => BatchPusher.Object,
                    SystemTime.Object,
                    FeatureFlags.Object,
                    Options.Object,
                    TelemetryService.Object,
                    Logger);
            }