<commit_before>﻿using System;
using System.Collections.Generic;
using System.Reflection;

namespace BosunReporter
{
    public sealed class MetricGroup<T> where T : BosunMetric
    {
        private readonly MetricsCollector _collector;
        private readonly string _name;
        private readonly Dictionary<string, T> _metrics = new Dictionary<string,T>();
        private readonly Func<string, T> _metricFactory;

        public string Name { get { return _name; } }

        internal MetricGroup(MetricsCollector collector, string name, Func<string, T> metricFactory = null)
        {
            _collector = collector;
            _name = name;
            _metricFactory = metricFactory ?? GetDefaultFactory();
        }

        public T this[string primaryTagValue]
        {
            get
            {
                T metric;
                if (_metrics.TryGetValue(primaryTagValue, out metric))
                    return metric;

                // not going to worry about concurrency here because GetMetric is already thread safe, and indempotent.
                metric = _collector.GetMetric(_name, _metricFactory(primaryTagValue));
                _metrics[primaryTagValue] = metric;
                
                return metric;
            }
        }

        private Func<string, T> GetDefaultFactory()
        {
            // get the constructor which takes a single string argument
            var constructor = typeof(T).GetConstructor(BindingFlags.Instance | BindingFlags.Public, null, new []{ typeof(string) }, null);
            if (constructor == null)
            {

                throw new Exception(
                    String.Format(
                        "Cannot create a MetricGroup for Type \"{0}\". It does not have a constructor which takes a single string argument. " +
                        "Either add a constructor with that signature, or use the metricFactory argument to define a custom factory.",
                        typeof(T).FullName));
            }

            return s => (T)constructor.Invoke(new[] { (object)s });
        }
    }
}
<commit_msg>Handle dictionary insert race condition.<commit_after>﻿using System;
using System.Collections.Generic;
using System.Reflection;

namespace BosunReporter
{
    public sealed class MetricGroup<T> where T : BosunMetric
    {
        private readonly object _dictionaryLock = new object();
        private readonly MetricsCollector _collector;
        private readonly string _name;
        private readonly Dictionary<string, T> _metrics = new Dictionary<string,T>();
        private readonly Func<string, T> _metricFactory;

        public string Name { get { return _name; } }

        internal MetricGroup(MetricsCollector collector, string name, Func<string, T> metricFactory = null)
        {
            _collector = collector;
            _name = name;
            _metricFactory = metricFactory ?? GetDefaultFactory();
        }

        public T this[string primaryTagValue]
        {
            get
            {
                T metric;
                if (_metrics.TryGetValue(primaryTagValue, out metric))
                    return metric;

                lock (_dictionaryLock)
                {
                    if (_metrics.TryGetValue(primaryTagValue, out metric))
                        return metric;

                    metric = _collector.GetMetric(_name, _metricFactory(primaryTagValue));
                    _metrics[primaryTagValue] = metric;
                    
                    return metric;
                }
            }
        }

        private Func<string, T> GetDefaultFactory()
        {
            // get the constructor which takes a single string argument
            var constructor = typeof(T).GetConstructor(BindingFlags.Instance | BindingFlags.Public, null, new []{ typeof(string) }, null);
            if (constructor == null)
            {

                throw new Exception(
                    String.Format(
                        "Cannot create a MetricGroup for Type \"{0}\". It does not have a constructor which takes a single string argument. " +
                        "Either add a constructor with that signature, or use the metricFactory argument to define a custom factory.",
                        typeof(T).FullName));
            }

            return s => (T)constructor.Invoke(new[] { (object)s });
        }
    }
}

{'fraction_non_alphanumeric': 0.07613868116927261, 'fraction_numerical': 0.00045320643553138455, 'mean_word_length': 1.7901390644753477, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7192592', 'n_tokens_mistral': 1049, 'n_tokens_neox': 991, 'n_words': 327}