Пример #1
0
        internal CountersBatchOperation(CounterStore parent, string counterStorageName, CountersBatchOptions batchOptions = null)
            : base(parent, counterStorageName)
        {
            if (batchOptions != null && batchOptions.BatchSizeLimit < 1)
            {
                throw new ArgumentException("batchOptions.BatchSizeLimit cannot be negative", "batchOptions");
            }

            defaultOptions    = batchOptions ?? new CountersBatchOptions(); //defaults do exist
            streamingStarted  = new AsyncManualResetEvent();
            batchOperationTcs = new TaskCompletionSource <bool>();
            cts           = new CancellationTokenSource();
            changesQueue  = new BlockingCollection <CounterChange>(defaultOptions.BatchSizeLimit);
            singleAuthUrl = string.Format("{0}/cs/{1}/singleAuthToken", ServerUrl, counterStorageName);

            OperationId        = Guid.NewGuid();
            disposed           = false;
            batchOperationTask = StartBatchOperation();
            if (AsyncHelpers.RunSync(() => streamingStarted.WaitAsync(TimeSpan.FromMilliseconds(DefaultOptions.StreamingInitializeTimeout))) == false ||
                batchOperationTask.IsFaulted)
            {
                throw new InvalidOperationException("Failed to start streaming batch.", batchOperationTask.Exception);
            }
            closeAndReopenStreamingTimer = CreateNewTimer();
        }
Пример #2
0
        public async Task CountersInitialize_with_EnsureDefaultCounterCreation_should_not_overwrite_existing_counters()
        {
            using (var server = GetNewServer(port: 8091))
            {
                using (var counterStore = new CounterStore
                {
                    Url = $"{server.DocumentStore.Url}:{server.Configuration.Port}",
                    Name = DefaultCounterStorageName
                })
                {
                    counterStore.Initialize(true);

                    await counterStore.IncrementAsync("G", "C");

                    await counterStore.DecrementAsync("G", "C2");
                }

                using (var counterStore = new CounterStore
                {
                    Url = $"{server.DocumentStore.Url}:{server.Configuration.Port}",
                    Name = DefaultCounterStorageName
                })
                {
                    counterStore.Initialize(true);
                    var summary = await counterStore.Admin.GetCountersByStorage(DefaultCounterStorageName);

                    Assert.Equal(2, summary.Count);
                    Assert.NotNull(summary.SingleOrDefault(x => x.Total == 1 && x.GroupName == "G" && x.CounterName == "C"));
                    Assert.NotNull(summary.SingleOrDefault(x => x.Total == -1 && x.GroupName == "G" && x.CounterName == "C2"));
                }
            }
        }
Пример #3
0
 protected CounterOperationsBase(CounterStore parent, string counterStorageName)
 {
     credentials        = parent.Credentials;
     jsonRequestFactory = parent.JsonRequestFactory;
     ServerUrl          = parent.Url;
     CounterStorageUrl  = string.Format(CultureInfo.InvariantCulture, "{0}/cs/{1}", ServerUrl, counterStorageName);
     countersConvention = parent.CountersConvention;
 }
Пример #4
0
        private async Task ImportIncrementalData(CounterConnectionStringOptions connectionString, Stream stream)
        {
            CountingStream sizeStream;
            JsonTextReader jsonReader;

            if (SmugglerHelper.TryGetJsonReaderForStream(stream, out jsonReader, out sizeStream) == false)
            {
                throw new InvalidOperationException("Failed to get reader for the data stream.");
            }

            if (jsonReader.TokenType != JsonToken.StartObject)
            {
                throw new InvalidDataException("StartObject was expected");
            }

            ICounterStore store = null;

            try
            {
                if (jsonReader.Read() == false && jsonReader.TokenType != JsonToken.StartArray)
                {
                    throw new InvalidDataException("StartArray was expected");
                }

                store = new CounterStore
                {
                    Url         = connectionString.Url,
                    Name        = connectionString.CounterStoreId,
                    Credentials = new OperationCredentials(connectionString.ApiKey, connectionString.Credentials)
                };
                store.Initialize(true);
                ShowProgress($"Initialized connection to counter store (name = {store.Name})");

                while (jsonReader.Read() && jsonReader.TokenType != JsonToken.EndArray)
                {
                    if (jsonReader.TokenType != JsonToken.StartObject)
                    {
                        continue;
                    }

                    var counterDelta = RavenJToken.ReadFrom(jsonReader).ToObject <CounterState>();
                    ShowProgress($"Importing counter {counterDelta.GroupName} - {counterDelta.CounterName}");
                    if (counterDelta.Sign == ValueSign.Negative)
                    {
                        counterDelta.Value = -counterDelta.Value;
                    }
                    store.Batch.ScheduleChange(counterDelta.GroupName, counterDelta.CounterName, counterDelta.Value);
                }

                ShowProgress("Finished import of the current file.");
                await store.Batch.FlushAsync().WithCancellation(CancellationToken).ConfigureAwait(false);
            }
            finally
            {
                store?.Dispose();
            }
        }
Пример #5
0
        public void TestMetricsMin()
        {
            var cs = new CounterStore();
            var c  = cs.GetCounter("1");

            foreach (var i in Enumerable.Range(0, 60))
            {
                c.RegisterEvent(new DateTime(2012, 01, 01, 3, i, i));
                c.RegisterEvent(new DateTime(2012, 01, 01, 3, 59 - i, 59 - i));
            }
            Assert.AreEqual(2, c.AvgEventsPerMinute);
        }
Пример #6
0
 internal CounterReplicationInformer(HttpJsonRequestFactory requestFactory, CounterStore counterStore, CountersConvention countersConvention, int delayTimeInMiliSec = 1000)
 {
     currentReadStripingBase = 0;
     ReplicationDestinations = new List <CounterReplicationDestination>();
     this.requestFactory     = requestFactory;
     this.counterStore       = counterStore;
     this.countersConvention = countersConvention;
     this.delayTimeInMiliSec = delayTimeInMiliSec;
     failureCounters         = new FailureCounters();
     firstTime             = true;
     lastReplicationUpdate = SystemTime.UtcNow;
     MaxIntervalBetweenUpdatesInMilliseconds = TimeSpan.FromMinutes(DefaultIntervalBetweenUpdatesInMinutes).TotalMilliseconds;
 }
Пример #7
0
        public void Test2()
        {
            var cs = new CounterStore();
            var c  = cs.GetCounter("1");

            c.TotalEvents = 88;
            c.RegisterEvent();

            Assert.AreEqual(89, c.TotalEvents);

            Assert.AreEqual(null, c.Comment);
            c.Comment = "123";
            Assert.AreEqual("123", c.Comment);
        }
Пример #8
0
        public async Task Between(SmugglerBetweenOptions <CounterConnectionStringOptions> betweenOptions)
        {
            if (betweenOptions.ReportProgress == null)
            {
                betweenOptions.ReportProgress = msg => { }
            }
            ;
            using (var source = new CounterStore
            {
                Url = betweenOptions.From.Url,
                Name = betweenOptions.From.CounterStoreId,
                Credentials = new OperationCredentials(betweenOptions.From.ApiKey, betweenOptions.From.Credentials)
            })
                using (var target = new CounterStore
                {
                    Url = betweenOptions.To.Url,
                    Name = betweenOptions.To.CounterStoreId,
                    Credentials = new OperationCredentials(betweenOptions.To.ApiKey, betweenOptions.To.Credentials)
                })
                {
                    source.Initialize(true);
                    ShowProgress($"Initialized connection to source counter store (name = {source.Name})");
                    target.Initialize(true);
                    ShowProgress($"Initialized connection to target counter store (name = {target.Name})");

                    var existingCounterGroupsAndNames = await target.Admin.GetCounterStorageNameAndGroups(token : CancellationToken).ConfigureAwait(false);

                    var counterSummaries = await source.Advanced.GetCounters(token : CancellationToken).ConfigureAwait(false);

                    ShowProgress($"Fetched counter data from source (there is data about {counterSummaries.Count} counters)");

                    foreach (var summary in counterSummaries)
                    {
                        if (existingCounterGroupsAndNames.Any(x => x.Group == summary.GroupName && x.Name == summary.CounterName))
                        {
                            ShowProgress($"Counter {summary.GroupName} - {summary.CounterName} is already there. Reset is performed");
                            await target.ResetAsync(summary.GroupName, summary.CounterName, CancellationToken)
                            .WithCancellation(CancellationToken)
                            .ConfigureAwait(false); //since it is a full import, the values are overwritten
                        }

                        ShowProgress($"Importing counter {summary.GroupName} - {summary.CounterName}");
                        target.Batch.ScheduleChange(summary.GroupName, summary.CounterName, summary.Total);
                    }

                    ShowProgress("Finished import...");
                    await target.Batch.FlushAsync().WithCancellation(CancellationToken).ConfigureAwait(false);
                }
        }
    }
Пример #9
0
            public async Task SynchronizationTopologyDiscovererSimpleTest()
            {
                using (CounterStore storeA = (CounterStore)NewRemoteCountersStore(DefaultCounterStorageName + "A"))
                    using (var storeB = NewRemoteCountersStore(DefaultCounterStorageName + "B"))
                        using (var storeC = NewRemoteCountersStore(DefaultCounterStorageName + "C"))
                            using (var storeD = NewRemoteCountersStore(DefaultCounterStorageName + "D"))
                                using (var storeE = NewRemoteCountersStore(DefaultCounterStorageName + "E"))
                                {
                                    await SetupReplicationAsync(storeA, storeB);
                                    await SetupReplicationAsync(storeB, storeC);
                                    await SetupReplicationAsync(storeC, storeD);
                                    await SetupReplicationAsync(storeD, storeE);
                                    await SetupReplicationAsync(storeE, storeA);

                                    await storeA.ChangeAsync("group", "counter", 2);
                                    await WaitForReplicationBetween(storeA, storeE, "group", "counter");

                                    var url = storeA.Url.ForCounter(DefaultCounterStorageName + "A1") + "/admin/replication/topology/view";

                                    var request = storeA
                                                  .JsonRequestFactory
                                                  .CreateHttpJsonRequest(new CreateHttpJsonRequestParams(null, url, HttpMethods.Post, storeA.Credentials, storeA.CountersConvention));

                                    var json     = (RavenJObject)request.ReadResponseJson();
                                    var topology = json.Deserialize <CountersReplicationTopology>(new DocumentConvention());

                                    Assert.NotNull(topology);
                                    Assert.Equal(5, topology.Servers.Count);
                                    Assert.Equal(5, topology.Connections.Count);


                                    topology.Connections.Single(x => x.Destination == storeA.Url.ForCounter(storeA.Name) && x.Source == storeE.Url.ForCounter(storeE.Name));
                                    topology.Connections.Single(x => x.Destination == storeB.Url.ForCounter(storeB.Name) && x.Source == storeA.Url.ForCounter(storeA.Name));
                                    topology.Connections.Single(x => x.Destination == storeC.Url.ForCounter(storeC.Name) && x.Source == storeB.Url.ForCounter(storeB.Name));
                                    topology.Connections.Single(x => x.Destination == storeD.Url.ForCounter(storeD.Name) && x.Source == storeC.Url.ForCounter(storeC.Name));
                                    topology.Connections.Single(x => x.Destination == storeE.Url.ForCounter(storeE.Name) && x.Source == storeD.Url.ForCounter(storeD.Name));

                                    foreach (var connection in topology.Connections)
                                    {
                                        Assert.Equal(ReplicatonNodeState.Online, connection.SourceToDestinationState);
                                        Assert.Equal(ReplicatonNodeState.Online, connection.DestinationToSourceState);
                                        Assert.NotNull(connection.Source);
                                        Assert.NotNull(connection.Destination);
                                        Assert.NotNull(connection.LastEtag);
                                        Assert.NotNull(connection.SendServerId);
                                        Assert.NotNull(connection.StoredServerId);
                                    }
                                }
            }
Пример #10
0
        internal static void ScriptOrderPrevRange()
        {
            if (HttpContext.Current == null)
            {
                return;
            }
            if (HttpContext.Current.Items[ResourceManager.scriptOrderkey] == null)
            {
                return;
            }

            CounterStore c = ((CounterStore)HttpContext.Current.Items[ResourceManager.scriptOrderkey]);

            c.counter = c.counter - 1000000;
        }
Пример #11
0
        public void TestMetricsHourSec()
        {
            var cs = new CounterStore();
            var c  = cs.GetCounter("1");

            foreach (var i in Enumerable.Range(0, 60))
            {
                foreach (var h in Enumerable.Range(0, 24))
                {
                    c.RegisterEvent(new DateTime(2012, 01, 01, h, 1, i));
                }
            }

            //        Assert.AreEqual(120, c.TotalEvents);
            Assert.AreEqual(24, c.AvgEventsPerSecond);
            Assert.AreEqual(60, c.AvgEventsPerHour);
        }
Пример #12
0
        protected ICounterStore NewRemoteCountersStore(string counterStorageName, bool createDefaultCounter = true, OperationCredentials credentials = null, RavenDbServer ravenServer = null)
        {
            ravenServer = ravenServer ?? this.RavenDbServer.Value;
            var serverUrl = ravenServer.SystemDatabase.ServerUrl;

            serverCount.AddOrUpdate(serverUrl, id => 1, (id, val) => val++);

            var counterStore = new CounterStore
            {
                Url         = GetServerUrl(true, serverUrl),
                Credentials = credentials ?? new OperationCredentials(null, CredentialCache.DefaultNetworkCredentials),
                Name        = counterStorageName + serverCount[serverUrl]
            };

            counterStore.Initialize(createDefaultCounter);
            return(counterStore);
        }
Пример #13
0
        public void Cannot_use_admin_endpoint_with_non_admin_apiKey()
        {
            string storeName;

            using (var store = NewRemoteCountersStore("TestStore")) //this will create the TestStore
            {
                storeName = store.Name;
            }

            Database.Server.Security.Authentication.EnableOnce();

            //GoodApiKey is with admin access to <system>
            ConfigureApiKey(servers[0].SystemDatabase, "thisIsApiKeyName", "thisIsSecret", storeName, true);

            //BadApiKey is without admin access to <system>
            ConfigureApiKey(servers[0].SystemDatabase, "NotThisIsApiKeyName", "thisIsSecret", storeName);

            using (var store = new CounterStore
            {
                Url = servers[0].SystemDatabase.ServerUrl,
                Name = storeName,
                Credentials = new OperationCredentials(BadApiKey, null)
            })
            {
                store.Initialize();
                var e = Assert.Throws <ErrorResponseException>(() => AsyncHelpers.RunSync(() => store.Admin.GetCounterStoragesNamesAsync()));

                Assert.Equal(HttpStatusCode.Forbidden, e.StatusCode);
            }

            using (var store = new CounterStore
            {
                Url = servers[0].SystemDatabase.ServerUrl,
                Name = storeName,
                Credentials = new OperationCredentials(GoodApiKey, null)
            })
            {
                store.Initialize();
                IReadOnlyList <string> storageNames = null;
                Assert.DoesNotThrow(() => storageNames = AsyncHelpers.RunSync(() => store.Admin.GetCounterStoragesNamesAsync()));

                Assert.Equal(1, storageNames.Count);
            }
        }
Пример #14
0
        private async System.Threading.Tasks.Task UpdateState()
        {
            var events = await CounterStore.AllEventsAfter(lastSequence).ConfigureAwait(false);

            foreach (var counterEvent in events)
            {
                switch (counterEvent.Value.EventCase)
                {
                case EventOneofCase.Added:
                    await DispatcherHelper.RunAsync(() => Counters.Add(new AutomatedCounter(counterEvent.Value.Id.ToGuid(), counterEvent.Value.Added.Name)));

                    break;

                case EventOneofCase.Removed:
                {
                    var counterId       = counterEvent.Value.Id.ToGuid();
                    var counterToRemove = Counters.SingleOrDefault(x => x.Id == counterId);
                    if (counterToRemove != null)
                    {
                        await DispatcherHelper.RunAsync(() => Counters.Remove(counterToRemove));
                    }
                }

                break;

                case EventOneofCase.NameChanged:
                {
                    var counterId       = counterEvent.Value.Id.ToGuid();
                    var counterToUpdate = Counters.SingleOrDefault(x => x.Id == counterId);
                    if (counterToUpdate != null)
                    {
                        await DispatcherHelper.RunAsync(() => counterToUpdate.Name = counterEvent.Value.NameChanged.Name);
                    }
                }

                break;
                }

                lastSequence = counterEvent.Key;
            }
        }
Пример #15
0
        public async Task When_Counter_has_apiKey_auth_then_operations_with_wrong_apiKey_should_fail()
        {
            String storeName;

            using (var store = NewRemoteCountersStore("TestStore")) //this will create the TestStore
            {
                storeName = store.Name;
                await store.IncrementAsync("G", "C");
            }

            Database.Server.Security.Authentication.EnableOnce();
            ConfigureApiKey(servers[0].SystemDatabase, "thisIsApiKeyName", "thisIsSecret", storeName);
            ConfigureApiKey(servers[0].SystemDatabase, "NotThisIsApiKeyName", "thisIsSecret", "NonExistingResourceName");

            using (var store = new CounterStore
            {
                Url = servers[0].SystemDatabase.ServerUrl,
                Name = storeName,
                Credentials = new OperationCredentials(BadApiKey, null)
            })
            {
                store.Initialize();
                var e = Assert.Throws <ErrorResponseException>(() => AsyncHelpers.RunSync(() => store.IncrementAsync("G", "C")));

                Assert.Equal(HttpStatusCode.Forbidden, e.StatusCode);
            }

            using (var store = new CounterStore
            {
                Url = servers[0].SystemDatabase.ServerUrl,
                Name = storeName,
                Credentials = new OperationCredentials(GoodApiKey, null)
            })
            {
                store.Initialize();
                Assert.DoesNotThrow(() => AsyncHelpers.RunSync(() => store.IncrementAsync("G", "C")));
            }
        }
Пример #16
0
        public void TestStore()
        {
            var cs = new CounterStore();
            var c1 = cs.GetCounter("c1");
            var c2 = cs.GetCounter("c2");

            Assert.AreEqual(0, c1.TotalEvents);
            Assert.AreEqual(0, c2.TotalEvents);

            c1.RegisterEvent();
            c1.RegisterEvent();
            c2.RegisterEvent();

            Assert.AreEqual(2, c1.TotalEvents);

            Assert.AreEqual(1 / 60, c1.AvgEventsPerMinute);


            Assert.AreEqual(1 / 24, c1.AvgEventsPerHour);

            Assert.AreEqual(1, c2.TotalEvents);


            var counterNames = cs.EnumerateCounters().OrderBy(a => a);

            Assert.AreEqual(2, counterNames.Count());
            Assert.AreEqual("c1", counterNames.First());
            Assert.AreEqual("c2", counterNames.Last());

            var c11 = cs.GetCounter("c1");

            Assert.AreEqual(2, c11.TotalEvents);

            cs.DeleteCounter("c1");
            counterNames = cs.EnumerateCounters().OrderBy(a => a);
            Assert.AreEqual(1, counterNames.Count());
            Assert.AreEqual("c2", counterNames.Last());
        }
Пример #17
0
 protected override void OnInitialized()
 {
     base.OnInitialized();
     CounterStore.AddStateChangeListener(UpdateView); //attach listener to the store
 }
Пример #18
0
        /// <summary>
        /// Export counter data to specified destination (a file or a stream)
        /// </summary>
        /// <param name="exportOptions">options to specify the source and destination of the export</param>
        /// <exception cref="UnauthorizedAccessException">The caller does not have the required permission.-or- specified a file that is read-only. </exception>
        /// <exception cref="DirectoryNotFoundException">The specified path is invalid (for example, it is on an unmapped drive). </exception>
        /// <exception cref="IOException">An I/O error occurred while creating the file. </exception>
        /// <exception cref="SmugglerException">Encapsulates exception that happens when actually exporting data. See InnerException for details.</exception>
        public async Task <CounterOperationState> ExportData(SmugglerExportOptions <CounterConnectionStringOptions> exportOptions)
        {
            if (exportOptions.From == null)
            {
                throw new ArgumentNullException("exportOptions.From");
            }

            if (String.IsNullOrWhiteSpace(exportOptions.ToFile) && exportOptions.ToStream == null)
            {
                throw new ArgumentException("ToFile or ToStream property in options must be non-null");
            }

            var result       = new CounterOperationState();
            var exportFolder = String.Empty;

            if (Options.Incremental)
            {
                ShowProgress("Starting incremental export..");
                exportFolder = CalculateExportFile(exportOptions, exportFolder);
            }
            else
            {
                ShowProgress("Starting full export...");
            }

            SmugglerException lastException = null;

            var ownedStream = exportOptions.ToStream == null;
            var stream      = exportOptions.ToStream ?? File.Create(exportOptions.ToFile);

            if (ownedStream)
            {
                ShowProgress("Export to dump file " + exportOptions.ToFile);
            }
            try
            {
                using (var counterStore = new CounterStore
                {
                    Url = exportOptions.From.Url,
                    Name = exportOptions.From.CounterStoreId,
                    Credentials = new OperationCredentials(exportOptions.From.ApiKey, exportOptions.From.Credentials)
                })
                    using (var gZipStream = new GZipStream(stream, CompressionMode.Compress, leaveOpen: true))
                        using (var streamWriter = new StreamWriter(gZipStream))
                        {
                            counterStore.Initialize();
                            var jsonWriter = new JsonTextWriter(streamWriter)
                            {
                                Formatting = Formatting.Indented
                            };
                            jsonWriter.WriteStartObject();
                            jsonWriter.WritePropertyName(Options.Incremental ? "CountersDeltas" : "CounterSnapshots"); //also for human readability
                            jsonWriter.WriteStartArray();

                            try
                            {
                                if (Options.Incremental)
                                {
                                    await ExportIncrementalData(counterStore, exportFolder, jsonWriter).WithCancellation(CancellationToken).ConfigureAwait(false);
                                }
                                else
                                {
                                    await ExportFullData(counterStore, jsonWriter).WithCancellation(CancellationToken).ConfigureAwait(false);
                                }
                            }
                            catch (SmugglerException e)
                            {
                                Debug.Assert(e.Data.Keys.Cast <string>().Contains("LastEtag"));
                                result.LastWrittenEtag = (long)e.Data["LastEtag"];
                                lastException          = e;
                                var operation = Options.Incremental ? "Incremental" : "Full";
                                ShowProgress($"{operation} Export failed. {e}");
                            }

                            jsonWriter.WriteEndArray();
                            jsonWriter.WriteEndObject();
                            streamWriter.Flush();
                        }

                if (lastException != null)
                {
                    throw lastException;
                }
                return(result);
            }
            finally
            {
                if (ownedStream && stream != null)
                {
                    stream.Flush();
                    stream.Dispose();
                    ShowProgress("Finished export and closed file...");
                }
                else
                {
                    ShowProgress("Finished export...");
                }
            }
        }
Пример #19
0
        //assumes that the caller has responsibility to handle data stream disposal ("stream" parameter)
        private async Task ImportFullData(CounterConnectionStringOptions connectionString, Stream stream)
        {
            CountingStream sizeStream;
            JsonTextReader jsonReader;

            if (SmugglerHelper.TryGetJsonReaderForStream(stream, out jsonReader, out sizeStream) == false)
            {
                throw new InvalidOperationException("Failed to get reader for the data stream.");
            }

            if (jsonReader.TokenType != JsonToken.StartObject)
            {
                throw new InvalidDataException("StartObject was expected");
            }

            ICounterStore store = null;

            try
            {
                if (jsonReader.Read() == false && jsonReader.TokenType != JsonToken.StartArray)
                {
                    throw new InvalidDataException("StartArray was expected");
                }

                store = new CounterStore
                {
                    Url         = connectionString.Url,
                    Name        = connectionString.CounterStoreId,
                    Credentials = new OperationCredentials(connectionString.ApiKey, connectionString.Credentials)
                };
                store.Initialize(true);

                ShowProgress($"Initialized connection to counter store (name = {store.Name})");
                var existingCounterGroupsAndNames = await store.Admin.GetCounterStorageNameAndGroups(token : CancellationToken)
                                                    .WithCancellation(CancellationToken)
                                                    .ConfigureAwait(false);

                while (jsonReader.Read() && jsonReader.TokenType != JsonToken.EndArray)
                {
                    if (jsonReader.TokenType != JsonToken.StartObject)
                    {
                        continue;
                    }

                    var counterInfo = (RavenJObject)RavenJToken.ReadFrom(jsonReader);

                    var delta       = Math.Abs(counterInfo.Value <long>("Positive")) - Math.Abs(counterInfo.Value <long>("Negative"));
                    var groupName   = counterInfo.Value <string>("Group");
                    var counterName = counterInfo.Value <string>("Name");

                    if (existingCounterGroupsAndNames.Any(x => x.Group == groupName && x.Name == counterName))
                    {
                        ShowProgress($"Counter {groupName} - {counterName} is already there. Reset is performed");
                        await store.ResetAsync(groupName, counterName, CancellationToken).ConfigureAwait(false); //since it is a full import, the values are overwritten
                    }

                    ShowProgress($"Importing counter {groupName} - {counterName}");
                    store.Batch.ScheduleChange(groupName, counterName, delta);
                }

                ShowProgress("Finished import...");
                await store.Batch.FlushAsync().WithCancellation(CancellationToken).ConfigureAwait(false);
            }
            finally
            {
                store?.Dispose();
            }
        }
Пример #20
0
 public void Dispose()
 {
     CounterStore.RemoveStateChangeListener(UpdateView);
 }