示例#1
0
        private Task <IList <string> > CheckUpdateDataIds(IList <CacheData> cacheDatas, IList <string> inInitializingCacheList)
        {
            StringBuilder sb = new StringBuilder();

            foreach (var cacheData in cacheDatas)
            {
                if (!cacheData.IsUseLocalConfig)
                {
                    sb.Append(cacheData.DataId).Append(Constants.WORD_SEPARATOR);
                    sb.Append(cacheData.Group).Append(Constants.WORD_SEPARATOR);
                    if (string.IsNullOrEmpty(cacheData.Tenant))
                    {
                        sb.Append(cacheData.MD5).Append(Constants.LINE_SEPARATOR);
                    }
                    else
                    {
                        sb.Append(cacheData.MD5).Append(Constants.WORD_SEPARATOR);
                        sb.Append(cacheData.Tenant).Append(Constants.LINE_SEPARATOR);
                    }
                    if (cacheData.IsInitializing)
                    {
                        inInitializingCacheList.Add(GroupKey.GetKeyTenant(cacheData.DataId, cacheData.Group, cacheData.Tenant));
                    }
                }
            }
            bool isInitializingCacheList = inInitializingCacheList.Count > 0;

            return(CheckUpdateConfigStr(sb.ToString(), isInitializingCacheList));
        }
            public async Task FiresMetricEventWhenRejected()
            {
                // Arrange

                var key      = AnyString;
                var groupKey = GroupKey.Named(key);

                var mockMetricEvents   = new Mock <IMetricEvents>();
                var mockBreakerInvoker = new Mock <IBreakerInvoker>();

                var mockBulkhead = new Mock <ISemaphoreBulkhead>();

                mockBulkhead.Setup(m => m.TryEnter()).Returns(false);
                mockBulkhead.SetupGet(m => m.Name).Returns(key);

                var mockBulkheadFactory = new Mock <IBulkheadFactory>(MockBehavior.Strict);

                mockBulkheadFactory.Setup(m => m.GetBulkhead(groupKey)).Returns(mockBulkhead.Object);

                var mockConfig = new MjolnirConfiguration {
                    UseCircuitBreakers = true
                };

                // The breaker invoker behavior doesn't matter here, we shouldn't get to the point
                // where we try to use it.
                var invoker = new BulkheadInvoker(mockBreakerInvoker.Object, mockBulkheadFactory.Object, mockMetricEvents.Object, mockConfig);
                var command = new ConfigurableKeyAsyncCommand(key);

                // Act + Assert

                await Assert.ThrowsAsync <BulkheadRejectedException>(() => invoker.ExecuteWithBulkheadAsync(command, CancellationToken.None));

                mockMetricEvents.Verify(m => m.RejectedByBulkhead(key, command.Name));
            }
示例#3
0
        private CacheData AddCacheDataIfAbsent(string dataId, string group)
        {
            CacheData cache = GetCache(dataId, group);

            if (cache != null)
            {
                return(cache);
            }

            string key = GroupKey.GetKey(dataId, group);

            cache = new CacheData(_configFilterChainManager, _localConfigInfoProcessor, _agent.GetName(), dataId, group);

            var cacheFromMap = GetCache(dataId, group);

            if (cacheFromMap != null)
            {
                cache = cacheFromMap;
                cache.IsInitializing = true;
            }
            else
            {
                int taskId = _cacheMap.Count / (int)UtilAndComs.PER_TASK_CONFIG_SIZE;
                cache.TaskId = taskId;
            }

            _cacheMap.AddOrUpdate(key, cache, (k, v) => cache);

            _logger.Info($"[{_agent.GetName()}] [subscribe] {key}");

            return(cache);
        }
 internal GroupResult(ResultsPerGroupForm form, DisplayRow displayRow, GroupKey groupKey, ResultData resultData)
 {
     _form       = form;
     _displayRow = displayRow;
     _groupKey   = groupKey;
     _resultData = resultData;
 }
        public void TryEnterAndReleaseALot()
        {
            var semaphore = new SemaphoreSlimIsolationSemaphore(GroupKey.Named("Test"), new TransientConfigurableValue <int>(5), new IgnoringStats());

            Assert.True(semaphore.TryEnter());
            Assert.True(semaphore.TryEnter());
            Assert.True(semaphore.TryEnter());
            Assert.True(semaphore.TryEnter());
            Assert.True(semaphore.TryEnter());
            Assert.False(semaphore.TryEnter());
            Assert.False(semaphore.TryEnter());
            Assert.False(semaphore.TryEnter());
            semaphore.Release();
            Assert.True(semaphore.TryEnter());
            Assert.False(semaphore.TryEnter());
            semaphore.Release();
            semaphore.Release();
            semaphore.Release();
            semaphore.Release();
            semaphore.Release();
            Assert.True(semaphore.TryEnter());
            Assert.True(semaphore.TryEnter());
            Assert.True(semaphore.TryEnter());
            semaphore.Release();
            Assert.True(semaphore.TryEnter());
            Assert.True(semaphore.TryEnter());
            Assert.True(semaphore.TryEnter());
            Assert.False(semaphore.TryEnter());
            Assert.False(semaphore.TryEnter());
            semaphore.Release();
            semaphore.Release();
            semaphore.Release();
            semaphore.Release();
            semaphore.Release();
        }
示例#6
0
        private IGroupBy GetGroup(GroupKey key)
        {
            switch (key)
            {
            case GroupKey.CityStatus:
                return(_cityStatus);

            case GroupKey.CitySex:
                return(_citySex);

            case GroupKey.CountryStatus:
                return(_countryStatus);

            case GroupKey.CountrySex:
                return(_countrySex);

            case GroupKey.City:
                return(_city);

            case GroupKey.Country:
                return(_country);

            case GroupKey.Sex:
                return(_sex);

            case GroupKey.Status:
                return(_status);

            case GroupKey.Interests:
                return(_interests);

            default:
                return(null);
            }
        }
示例#7
0
        public void Construct_WhenMaxConcurrentConfigIsInvalid_DoesSomething()
        {
            // Arrange

            var       key                  = AnyString;
            var       groupKey             = GroupKey.Named(key);
            const int invalidMaxConcurrent = -1;
            var       mockMetricEvents     = new Mock <IMetricEvents>(); // Not Strict: we're not testing the events here.

            var mockConfig = new MjolnirConfiguration
            {
                BulkheadConfigurations = new Dictionary <string, BulkheadConfiguration>
                {
                    {
                        groupKey.Name,
                        new BulkheadConfiguration
                        {
                            MaxConcurrent = invalidMaxConcurrent
                        }
                    }
                }
            };

            var mockLogFactory = new Mock <IMjolnirLogFactory>(MockBehavior.Strict);

            mockLogFactory.Setup(m => m.CreateLog <SemaphoreBulkheadHolder>()).Returns(new DefaultMjolnirLog <SemaphoreBulkheadHolder>());

            // Act + Assert

            var exception = Assert.Throws <ArgumentOutOfRangeException>(() => new SemaphoreBulkheadHolder(groupKey, mockMetricEvents.Object, mockConfig, mockLogFactory.Object));

            Assert.Equal("maxConcurrent", exception.ParamName);
            Assert.Equal(invalidMaxConcurrent, exception.ActualValue);
        }
示例#8
0
        /// <summary>
        ///  Handle request from Peers and forward to the correct local Group instance
        /// </summary>
        public async Task GetAsync(string groupName, string key, Stream sink, ICacheControl cacheControl, CancellationToken ct)
        {
            SemaphoreHolder limiter;

            try
            {
                limiter = await _concurrencyLimiter.AcquireAsync(TimeSpan.Zero).ConfigureAwait(false);
            }
            catch (TimeoutException)
            {
                throw new ServerBusyException("Too many concurrent connection");
            }

            using (limiter)
            {
                var groupKey = new GroupKey {
                    GroupName = groupName, Endpoint = this.Endpoint
                };
                var found = GroupCache.GroupCache.GetGroup(groupKey, out Group group);
                if (!found)
                {
                    throw new GroupNotFoundException($"no such group: {groupName}");
                }
                group.Stats.TraceConcurrentServerRequests(_concurrencyLimit - _concurrencyLimiter.CurrentCount);
                group.Stats.TraceServerRequests(groupName);

                // We received a request from a peer, we need to download it locally and not forward to peer
                // because forwarding to peer would cause infinite loop if using different peer list
                await group.GetAsyncLocallyAsync(key, sink, cacheControl, ct);
            }
        }
示例#9
0
            public SemaphoreBulkheadHolder(GroupKey key, IMetricEvents metricEvents, MjolnirConfiguration config, IMjolnirLogFactory logFactory)
            {
                _key          = key;
                _metricEvents = metricEvents ?? throw new ArgumentNullException(nameof(metricEvents));
                _config       = config ?? throw new ArgumentNullException(nameof(config));

                if (logFactory == null)
                {
                    throw new ArgumentNullException(nameof(logFactory));
                }

                _log = logFactory.CreateLog <SemaphoreBulkheadHolder>();
                if (_log == null)
                {
                    throw new InvalidOperationException($"{nameof(IMjolnirLogFactory)} implementation returned null from {nameof(IMjolnirLogFactory.CreateLog)} for type {typeof(SemaphoreBulkheadHolder)}, please make sure the implementation returns a non-null log for all calls to {nameof(IMjolnirLogFactory.CreateLog)}");
                }

                // The order of things here is very intentional.
                // We get the MaxConcurrent value first and then initialize the semaphore bulkhead.
                // The change handler is registered after that. The order ought to help avoid a
                // situation where we might fire a config change handler before we add the
                // semaphore to the dictionary, potentially trying to add two entries with
                // different values in rapid succession.

                var value = _config.GetBulkheadConfiguration(key.Name).MaxConcurrent;

                _bulkhead = new SemaphoreBulkhead(_key, value);

                // On change, we'll replace the bulkhead. The assumption here is that a caller
                // using the bulkhead will have kept a local reference to the bulkhead that they
                // acquired a lock on, and will release the lock on that bulkhead and not one that
                // has been replaced after a config change.
                _config.OnConfigurationChanged(c => c.GetBulkheadConfiguration(key.Name).MaxConcurrent, UpdateMaxConcurrent);
            }
            public void FiresMetricEventWhenEnteringAndLeavingBulkheadAndCommandFails()
            {
                // Arrange

                var key      = AnyString;
                var groupKey = GroupKey.Named(key);

                var mockMetricEvents   = new Mock <IMetricEvents>();
                var mockBreakerInvoker = new Mock <IBreakerInvoker>();

                var mockBulkhead = new Mock <ISemaphoreBulkhead>();

                mockBulkhead.Setup(m => m.TryEnter()).Returns(true);
                mockBulkhead.SetupGet(m => m.Name).Returns(key);

                var mockBulkheadFactory = new Mock <IBulkheadFactory>(MockBehavior.Strict);

                mockBulkheadFactory.Setup(m => m.GetBulkhead(groupKey)).Returns(mockBulkhead.Object);

                var mockConfig = new MjolnirConfiguration {
                    UseCircuitBreakers = false
                };
                // The breaker invoker behavior doesn't matter here, we shouldn't get to the point
                // where we try to use it. Pass a "false" value for useCircuitBreakers to help
                // ensure that.
                var invoker = new BulkheadInvoker(mockBreakerInvoker.Object, mockBulkheadFactory.Object, mockMetricEvents.Object, mockConfig);
                var command = new ConfigurableKeyThrowingCommand(key);

                // Act + Assert

                Assert.Throws <ExpectedTestException>(() => invoker.ExecuteWithBulkhead(command, CancellationToken.None));

                mockMetricEvents.Verify(m => m.EnterBulkhead(key, command.Name));
                mockMetricEvents.Verify(m => m.LeaveBulkhead(key, command.Name));
            }
            public override string ToString()
            {
                StringBuilder sb = new StringBuilder("UsageInfo(");
                string        indexingDepthsString = indexingDepths.ToString();

                if (indexingDepthsString.Length > 0)
                {
                    sb.Append("indexingDepths=");
                    sb.Append(indexingDepthsString);
                }
                sb.Append(")");
                int count = 0;

                foreach (var entry in groups)
                {
                    GroupKey groupKey = entry.Key;
                    sb.AppendLine();
                    sb.Append("[");
                    sb.Append(count++);
                    sb.Append("] ");
                    sb.Append(entry.Value.Count);
                    sb.Append(" ");
                    foreach (ExpressionWithBinding eb in groupKey)
                    {
                        sb.Append("(");
                        sb.Append(eb);
                        sb.Append(")");
                    }
                }
                return(sb.ToString());
            }
示例#12
0
 private static void AssertInvalidName(string name)
 {
     Assert.Throws <ArgumentException>(() =>
     {
         GroupKey.Named(name);
     });
 }
示例#13
0
        private async Task <List <string> > CheckUpdateDataIds(List <CacheData> cacheDatas, List <string> inInitializingCacheList)
        {
            StringBuilder sb = new StringBuilder();

            foreach (CacheData cacheData in cacheDatas)
            {
                if (!cacheData.IsUseLocalConfig)
                {
                    sb.Append(cacheData.DataId).Append(Constants.WORD_SEPARATOR);
                    sb.Append(cacheData.Group).Append(Constants.WORD_SEPARATOR);
                    if (cacheData.Tenant.IsNullOrWhiteSpace())
                    {
                        sb.Append(cacheData.Md5).Append(Constants.LINE_SEPARATOR);
                    }
                    else
                    {
                        sb.Append(cacheData.Md5).Append(Constants.WORD_SEPARATOR);
                        sb.Append(cacheData.Tenant).Append(Constants.LINE_SEPARATOR);
                    }

                    if (cacheData.IsInitializing)
                    {
                        // It updates when cacheData occours in cacheMap by first time.
                        inInitializingCacheList
                        .Add(GroupKey.GetKeyTenant(cacheData.DataId, cacheData.Group, cacheData.Tenant));
                    }
                }
            }

            var isInitializingCacheList = inInitializingCacheList != null && inInitializingCacheList.Any();

            return(await CheckUpdateConfigStr(sb.ToString(), isInitializingCacheList));
        }
示例#14
0
        public static bool TryParse(string str, out GroupKey key)
        {
            switch (str)
            {
            case "sex":
                key = GroupKey.Sex;
                return(true);

            case "status":
                key = GroupKey.Status;
                return(true);

            case "country":
                key = GroupKey.Country;
                return(true);

            case "city":
                key = GroupKey.City;
                return(true);

            case "interests":
                key = GroupKey.Interest;
                return(true);

            default:
                key = default(GroupKey);
                return(false);
            }
        }
示例#15
0
        public CommonResponse RequestReply(CommonRequest request)
        {
            if (request is ConfigChangeNotifyRequest configChangeNotifyRequest)
            {
                string groupKey = GroupKey.GetKeyTenant(configChangeNotifyRequest.DataId, configChangeNotifyRequest.Group, configChangeNotifyRequest.Tenant);

                if (_cacheMap.TryGetValue(groupKey, out var cacheData))
                {
                    if (configChangeNotifyRequest.ContentPush &&
                        cacheData.LastModifiedTs < configChangeNotifyRequest.LastModifiedTs)
                    {
                        cacheData.SetContent(configChangeNotifyRequest.Content);
                        cacheData.Type = configChangeNotifyRequest.Type;
                        cacheData.CheckListenerMd5();
                    }

                    cacheData.IsListenSuccess = false;

                    // notifyListenConfig
                    _func.Invoke().Wait();
                }

                _logger?.LogDebug("Config RequestReply => {0}", request.ToJsonString());

                return(new ConfigChangeNotifyResponse());
            }

            return(null);
        }
            public void SetsExecutionTimeOnCommandWhenInvokedWithoutBreakerAndCommandFails()
            {
                // Arrange

                var key      = AnyString;
                var groupKey = GroupKey.Named(key);

                var mockMetricEvents   = new Mock <IMetricEvents>();
                var mockBreakerInvoker = new Mock <IBreakerInvoker>();

                var mockBulkhead = new Mock <ISemaphoreBulkhead>();

                mockBulkhead.Setup(m => m.TryEnter()).Returns(true);
                mockBulkhead.SetupGet(m => m.Name).Returns(key);

                var mockBulkheadFactory = new Mock <IBulkheadFactory>(MockBehavior.Strict);

                mockBulkheadFactory.Setup(m => m.GetBulkhead(groupKey)).Returns(mockBulkhead.Object);

                var mockConfig = new MjolnirConfiguration {
                    UseCircuitBreakers = false
                };
                // Pass false for useCircuitBreakers to bypass the breaker; we're testing that here.
                var invoker = new BulkheadInvoker(mockBreakerInvoker.Object, mockBulkheadFactory.Object, mockMetricEvents.Object, mockConfig);
                var command = new ConfigurableKeyThrowingCommand(key);

                // Act + Assert

                Assert.Throws <ExpectedTestException>(() => invoker.ExecuteWithBulkhead(command, CancellationToken.None));

                Assert.True(command.ExecutionTimeMillis > 0);
            }
        public CacheData AddCacheDataIfAbsent(string dataId, string group, string tenant)
        {
            CacheData cache = GetCache(dataId, group, tenant);

            if (cache != null)
            {
                return(cache);
            }

            string    key          = GroupKey.GetKey(dataId, group, tenant);
            CacheData cacheFromMap = GetCache(dataId, group, tenant);

            // multiple listeners on the same dataid+group and race condition,so double check again
            // other listener thread beat me to set to cacheMap
            if (cacheFromMap != null)
            {
                cache = cacheFromMap;

                // reset so that server not hang this check
                cache.IsInitializing = true;
            }
            else
            {
                cache = new CacheData(_configFilterChainManager, _agent.GetName(), dataId, group, tenant);

                int taskId = _cacheMap.Count / CacheData.PerTaskConfigSize;
                cache.TaskId = taskId;
            }

            _cacheMap.AddOrUpdate(key, cache, (x, y) => cache);

            _logger?.LogInformation("[{0}] [subscribe] {1}", this._agent.GetName(), key);

            return(cache);
        }
示例#18
0
        private async Task <CacheData> AddCacheDataIfAbsent(string dataId, string group, string tenant)
        {
            var cache = GetCache(dataId, group, tenant);

            if (cache != null)
            {
                return(cache);
            }

            string key          = GroupKey.GetKeyTenant(dataId, group, tenant);
            var    cacheFromMap = GetCache(dataId, group, tenant);

            if (cacheFromMap != null)
            {
                cache = cacheFromMap;
                cache.IsInitializing = true;
            }
            else
            {
                cache = new CacheData(_configFilterChainManager, _localConfigInfoProcessor, _agent.GetName(), dataId, group, tenant);
                if (_enableRemoteSyncConfig)
                {
                    string content = await GetServerConfig(dataId, group, tenant);

                    cache.Content = content;
                }
            }

            _cacheMap.AddOrUpdate(key, cache, (k, v) => cache);

            _logger.Info($"[{_agent.GetName()}] [subscribe] {key}");

            return(cache);
        }
示例#19
0
        public List <string> GetGroupMembers(GroupKey groupKey)
        {
            var group = GetGroup(groupKey);
            var list  = group.Users;

            return(list);
        }
示例#20
0
    bool IEqualityComparer.Equals(object x, object y)
    {
        GroupKey gkx = x as GroupKey;
        GroupKey gky = y as GroupKey;

        return((gkx == null || gky == null) ? false : gkx.ComponentCode == gky.ComponentCode && gkx.Key == gky.Key);
    }
示例#21
0
        public void Construct_WithIsolationKey_UsesIsolationKeyAsAllKeys()
        {
            var command = new KeyTestCommand("test", "foo");

            Assert.Equal(GroupKey.Named("foo"), command.BreakerKey);
            Assert.Equal(GroupKey.Named("foo"), command.PoolKey);
        }
        internal void RemoveCache(string dataId, string group, string tenant = null)
        {
            string groupKey = tenant == null?GroupKey.GetKey(dataId, group) : GroupKey.GetKeyTenant(dataId, group, tenant);

            _cacheMap.TryRemove(groupKey, out _);

            _logger?.LogInformation("[{0}] [unsubscribe] {1}", this._agent.GetName(), groupKey);
        }
示例#23
0
        internal StandardCommandMetrics(GroupKey key, IFailurePercentageCircuitBreakerConfig config, IClock clock, IMjolnirLogFactory logFactory)
        {
            _config = config ?? throw new ArgumentNullException(nameof(config));
            _clock  = clock ?? throw new ArgumentNullException(nameof(clock));

            _key = key;
            _resettingNumbersBucket = new ResettingNumbersBucket(_key, _clock, _config, logFactory);
        }
            public void Run()
            {
                var mockMetrics = CreateMockMetricsWithSnapshot(_metricsTotal, _metricsPercent);
                var properties  = CreateBreakerProperties(_breakerTotal, _breakerPercent, 30000);
                var breaker     = new FailurePercentageCircuitBreaker(GroupKey.Named("Test"), mockMetrics.Object, new IgnoringStats(), properties);

                Assert.NotEqual(_shouldTrip, breaker.IsAllowing());
            }
示例#25
0
 public IActionResult GetGroupPhones([FromBody] GroupKey groupKey)
 {
     if (!ModelState.IsValid)
     {
         return(BadRequest(ModelState));
     }
     return(Ok(_groupsService.GetGroupPhones(groupKey)));
 }
示例#26
0
        private void RemoveCache(string dataId, string group, string tenant)
        {
            var groupKey = GroupKey.GetKeyTenant(dataId, group, tenant);

            _cacheMap.TryRemove(groupKey, out _);

            _logger?.LogInformation("[{0}] [unsubscribe] {1}", GetNameInner(), groupKey);
        }
            public void Run()
            {
                var mockMetrics = CreateMockMetricsWithSnapshot(_metricsTotal, _metricsPercent);
                var config      = CreateMockBreakerConfig(_breakerTotal, _breakerPercent, 30000);
                var breaker     = new FailurePercentageCircuitBreaker(GroupKey.Named("Test"), mockMetrics.Object, new IgnoringMetricEvents(), config.Object, new DefaultMjolnirLogFactory());

                Assert.NotEqual(_shouldTrip, breaker.IsAllowing());
            }
示例#28
0
        public void DeleteGroup(GroupKey groupKey)
        {
            var exists = _groupsRepository.DeleteGroup(groupKey.PhoneNumber, groupKey.Name);

            if (exists == null)
            {
                throw new Exception("Group doesn't exist!");
            }
        }
示例#29
0
        //se va crea doar cheia
        public void NewGroup(GroupKey groupKey)
        {
            var exists = _groupsRepository.AddGroup(groupKey.PhoneNumber, groupKey.Name);

            if (exists != null)
            {
                throw new Exception("Group with the same name and admin already exists!");
            }
        }
            public void SetsBreakerKey()
            {
                var key      = AnyString;
                var expected = GroupKey.Named(key);

                var command = new TestCommand(AnyString, key, AnyString, ValidTimeout);

                Assert.Equal(expected, command.BreakerKey);
            }
示例#31
0
 internal GroupResult(ResultsPerGroupForm form, DisplayRow displayRow, GroupKey groupKey, ResultData resultData)
 {
     _form = form;
     _displayRow = displayRow;
     _groupKey = groupKey;
     _resultData = resultData;
 }
示例#32
0
 private void btnRequery_Click(object sender, EventArgs e)
 {
     var halfLifeCalculator = new HalfLifeCalculator(Workspace, HalfLifeSettings)
                                  {
                                      ByFile = cbxGroupByFile.Checked,
                                  };
     using (var longWaitDialog = new LongWaitDialog(TopLevelControl, "Calculating Half Lives"))
     {
         var longOperationBroker = new LongOperationBroker(halfLifeCalculator.Run, longWaitDialog);
         if (!longOperationBroker.LaunchJob())
         {
             return;
         }
     }
     bool byCohort = cbxGroupByCohort.Checked;
     bool byTimePoint = cbxGroupByTimePoint.Checked;
     bool bySample = cbxGroupBySample.Checked;
     bool byFile = cbxGroupByFile.Checked;
     var displayRows = new List<DisplayRow>();
     foreach (var resultRow in halfLifeCalculator.ResultRows)
     {
         var displayRow = new DisplayRow(halfLifeCalculator, resultRow);
         var rowDatasByCohort = new Dictionary<GroupKey, List<HalfLifeCalculator.ProcessedRowData>>();
         foreach (var halfLife in resultRow.HalfLives)
         {
             if (resultRow.HalfLives.Count > 1 && string.IsNullOrEmpty(halfLife.Key) != byCohort)
             {
                 continue;
             }
             foreach (var rowData in halfLife.Value.FilteredRowDatas)
             {
                 GroupKey cohortKey = new GroupKey(
                     byCohort ? rowData.RawRowData.MsDataFile.Cohort : null,
                     byTimePoint ? rowData.RawRowData.MsDataFile.TimePoint : null,
                     bySample ? rowData.RawRowData.MsDataFile.Sample : null,
                     byFile ? rowData.RawRowData.MsDataFile.Name : null);
                 List<HalfLifeCalculator.ProcessedRowData> list;
                 if (!rowDatasByCohort.TryGetValue(cohortKey, out list))
                 {
                     list = new List<HalfLifeCalculator.ProcessedRowData>();
                     rowDatasByCohort.Add(cohortKey, list);
                 }
                 list.Add(rowData);
             }
         }
         foreach (var cohortRowDatas in rowDatasByCohort)
         {
             displayRow.Results.Add(cohortRowDatas.Key, new GroupResult(this, displayRow, cohortRowDatas.Key, new ResultData(cohortRowDatas.Value)));
         }
         displayRows.Add(displayRow);
     }
     var viewInfo = bindingSource1.ViewInfo;
     var dataSchema = new TopographDataSchema(Workspace);
     if (viewInfo == null || "default" == viewInfo.Name)
     {
         viewInfo= new ViewInfo(ColumnDescriptor.RootColumn(dataSchema, typeof(DisplayRow)),
             GetDefaultViewSpec(halfLifeCalculator.ByProtein));
     }
     var viewContext = new TopographViewContext(Workspace, typeof (DisplayRow), displayRows,
         GetDefaultViewSpec(halfLifeCalculator.ByProtein));
     bindingSource1.SetViewContext(viewContext, viewInfo);
     bindingSource1.RowSource = displayRows;
     dataGridViewSummary.Rows.Clear();
     SetSummary("Tracer %", displayRows.Select(dr=>dr.Results).SelectMany(r=>r.Values
         .Select(cohortResult=>cohortResult.GetResultData().TracerPercentByArea)));
     SetSummary("Precursor Enrichment", displayRows.Select(dr=>dr.Results).SelectMany(r=>r.Values
         .Select(cohortResult=>cohortResult.GetResultData().IndPrecursorEnrichment)));
     SetSummary("Turnover", displayRows.Select(dr=>dr.Results).SelectMany(r=>r.Values
         .Select(cohortResult=>cohortResult.GetResultData().IndTurnover)));
     SetSummary("Area Under Curve", displayRows.Select(dr=>dr.Results).SelectMany(r=>r.Values
         .Select(cohortResult=>cohortResult.GetResultData().AreaUnderCurve)));
 }