private Lazy<TimeSeriesCellResponseEvent> QueueRequestInternal(CarbonTimeSeriesCellRequest request)
        {
            DateTime badTime;
            if (mBadRequests.TryGetValue(request.Key, out badTime))
            {
                // If bad request was sent within one minute, skip it.
                if ((DateTime.Now - badTime).TotalMinutes < 1)
                {
                    return null;
                }

                mBadRequests.TryRemove(request.Key, out badTime);
            }

            mDequeueSignal.Set();

            return mRequests.GetOrAdd(request.Key,
                cellRequest => new Lazy<TimeSeriesCellResponseEvent>(
                    () => new TimeSeriesCellResponseEvent(request)));
        }
 public bool QueueRequest(CarbonTimeSeriesCellRequest request)
 {
     return QueueRequestInternal(request) != null;
 }
 public object GetCachedValue(CarbonTimeSeriesCellRequest request)
 {
     object o;
     return mCachedResults.TryGetValue(request.Key, out o) ? o : null;
 }
 public TimeSeriesCellResponseEvent(CarbonTimeSeriesCellRequest timeSeriesCellRequest)
 {
     mTimeSeriesCellRequest = timeSeriesCellRequest;
     mEvent = new ManualResetEvent(false);
 }
        private void AddResultToCache(IReadOnlyCollection<ITimeSeries> rows, 
            IDictionary<string, string> filters, 
            IReadOnlyCollection<string> fields, 
            string requestType, 
            IReadOnlyCollection<TimeSeriesCellResponseEvent> responseEvents)
        {
            if (rows == null) return;
            if (rows.Count == 0) return;
            if (fields == null || fields.Count == 0) return;
            var keyFieldDef = mClient.GetCarbonField("date");

            var hasResult = new HashSet<string>();
            var requestsLookup = new Dictionary<string, TimeSeriesCellResponseEvent>();
            foreach (var responseEvent in responseEvents)
            {
                if (!requestsLookup.ContainsKey(responseEvent.SeriesCellRequest.Key))
                {
                    requestsLookup[responseEvent.SeriesCellRequest.Key] = responseEvent;
                }
            }

            foreach (var row in rows.Where(row => row.Series != null))
            {
                foreach (var series in row.Series)
                {
                    if (!series.ContainsKey("date")) continue;
                    var date = (DateTime)series["date"].ConvertMessagePackObject(keyFieldDef);

                    var match = true;

                    if (filters != null)
                    {
                        foreach (var filter in filters)
                        {
                            var columnName = filter.Key;
                            var reqValue = filter.Value;
                            MessagePackObject columnValue;
                            if (!series.TryGetValue(columnName, out columnValue) ||
                                reqValue.Equals(columnValue.ToString())) continue;
                            match = false;
                            break;
                        }
                    }

                    if (!match) continue;

                    foreach (var field in fields)
                    {
                        if(field == "date") continue;
                        if(!series.ContainsKey(field)) continue;
                        var carbonField = mClient.GetCarbonField(field);
                        if (carbonField == null) continue;
                        var o = series[field].ConvertMessagePackObject(carbonField);
                        if (o == null) continue;

                        var key = new CarbonTimeSeriesCellRequest(row.Identifier, requestType,
                            date, field, filters);

                        SLog.log.InfoFormat("Adding result for {0}", key);
                        mCachedResults.AddOrUpdate(key.Key, o, (request, oldO) => o);

                        TimeSeriesCellResponseEvent responseEvent;
                        if (!requestsLookup.TryGetValue(key.Key, out responseEvent)) continue;
                        SLog.log.InfoFormat("Event hashcode {0}", responseEvent.Event.GetHashCode());
                        responseEvent.Event.Set();
                        SLog.log.InfoFormat("Notify for request {0}", key);
                        if (!hasResult.Contains(key.Key))
                        {
                            hasResult.Add(key.Key);
                        }
                    }
                }
            }

            foreach (var req in responseEvents)
            {
                if (hasResult.Contains(req.SeriesCellRequest.Key)) continue;
                SLog.log.InfoFormat("Set NULL for request {0}", req);
                mBadRequests.TryAdd(req.SeriesCellRequest.Key, DateTime.Now);
                mCachedResults.AddOrUpdate(req.SeriesCellRequest.Key, (object)null, (request, o) => null);
            }
        }       
        public object GetResult(CarbonTimeSeriesCellRequest request)
        {
            var responseEvent = QueueRequestInternal(request);

            if (responseEvent == null) return null;

            if (!responseEvent.Value.Event.WaitOne(TimeSpan.FromMinutes(1)))
            {
                SLog.log.InfoFormat("Event hashcode {0}", responseEvent.Value.Event.GetHashCode());

                SLog.log.ErrorFormat("Timeout when waiting for request {0}", request);
            }

            try
            {
                responseEvent.Value.Dispose();
            }
            catch (Exception e)
            {
                SLog.log.ErrorFormat("Exception when disposing response event : {0}", e);
            }

            object o;
            if (mCachedResults.TryGetValue(request.Key, out o)) return o;

            return null;
        }