/** * Returns the ValueSet that corresponds to requestTime. */ public IValueSet GetValues(ITime requestedTime, IQuantity quantity, IElementSet elementSet, PrefetchManager prefetchManager, ILink link) { try { // generate the key of the buffer entry we're looking for var key = ValueSetEntry.CreateKey(webServiceManager.FindServiceIdForQuantity(quantity.ID), quantity.ID, elementSet.ID, requestedTime, scenarioId); traceFile.Append("GetValues: " + key); var mapValueSet = client.getMap<string, ValueSetEntry>("valueSet"); var mapElementSet = client.getMap<string, ElementSetEntry>("elementSet"); var queueValueSetRequest = client.getQueue<ValueSetRequestEntry>("valueSetRequest"); // record this request statistics.Add("GetValuesCount", 1); // measure our wait time var waitStopwatch = Stopwatch.StartNew(); // see if the requested values are in the cache var valueSetEntry = mapValueSet.get(key); // if the value set does not exist then request it if (valueSetEntry == null) { traceFile.Append("Requesting Value Set: " + key); // insert the element set if necessary if (elementSetsPut.Contains(elementSet.ID) == false) { elementSetsPut.Add(elementSet.ID); mapElementSet.put(elementSet.ID, new ElementSetEntry(elementSet)); } while (valueSetEntry == null) { // if we're prefetching, we may have already requested this // value set in a previous prefetch that hasn't been fulfilled // yet in which case we do not want to issue the request again. if (prefetchManager.timeIsFetched(link, (TimeStamp)requestedTime) == false) { // insert the request into the queue var insertRequestStopwatch = Stopwatch.StartNew(); // create the request entry var valueSetRequestEntry = new ValueSetRequestEntry(webServiceManager.FindServiceIdForQuantity(quantity.ID), quantity.ID, elementSet.ID, Utils.ITimeToDateTime(requestedTime), scenarioId); // BLOCKING queueValueSetRequest.put(valueSetRequestEntry); statistics.Add("RequestInsertTimeMS", insertRequestStopwatch.ElapsedMilliseconds); traceFile.Append("RequestInsertTime:" + string.Format("{0:0.0}", insertRequestStopwatch.ElapsedMilliseconds) + "ms"); } // PERFORMANCE STUDY: start delay at 100 and double each time // we check and it's not available // poll for the value set var delay = 1000; while (true) { // we know that the value set is not in the cache since // we just checked that above, so wait immediately after // making the request Thread.Sleep(delay); valueSetEntry = mapValueSet.get(key); if (valueSetEntry != null) { break; } //delay *= 2; traceFile.Append(string.Format("Waiting ({0}) For Value Set: ({1})", delay, key)); if (delay > 20000) { statistics.Add("RequestRetry", 1); break; } } } } statistics.Add("CacheWaitTimeMS", waitStopwatch.ElapsedMilliseconds); traceFile.Append("WaitTime:" + string.Format("{0:0.0}", waitStopwatch.ElapsedMilliseconds) + "ms"); return new ScalarSet(valueSetEntry.Values()); } catch (Exception e) { traceFile.Exception(e); return null; } }
public void Update(ILink link) { // don't do anything if we're disabled if (isEnabled == false) { return; } // see when this quantity was last requested on this link var lastRequestedTime = prefetchMonitor.lastRequestedTime(link.ID, link.SourceQuantity.ID); // if it never has been requested, then no one needs this // yet, and we can't do any prefetching at all since we don't // know what time to start prefetching until we get the // first request if (lastRequestedTime.ModifiedJulianDay == 0) { return; } // there has been at least one request for values for this // quantity, so we should prefetch up to the limit var linkId = link.ID; var quantityId = link.SourceQuantity.ID; var elementSet = link.TargetElementSet; // start prefetching from the latest fetched time on this link var prefetchTime = prefetchMonitor.latestFetchTime(link); // see what the time limit is for how far we want to prefetch var prefetchLimit = prefetchMonitor.getTimeLimit(); // prefetch up to the prefetch limit while (true) { // see what the next estimated request time after the latest // prefetch time is and what the prefetch limit is prefetchTime = prefetchMonitor.nextEstTimeReq(prefetchTime, linkId, quantityId); // stop when we pass the prefetch limit if (prefetchTime.ModifiedJulianDay > prefetchLimit.ModifiedJulianDay) { break; } // see if we've already requested this time for this // link ourselves, in which case we don't need to bother checking if (prefetchMonitor.timeIsFetched(link, prefetchTime) == true) { continue; } // log the prefetch status var prefetchCompletion = CalculateTimePercentage(prefetchMonitor.getTimeHorizon().Start, prefetchTime, prefetchLimit); traceFile.Append(string.Format("Prefetch:Link{0}/{1}:{2}-{3}:{4}%", linkId, quantityId, prefetchTime, prefetchLimit, (int)prefetchCompletion)); // generate the key for the next time to prefetchh var key = ValueSetEntry.CreateKey(webServiceManager.FindServiceIdForQuantity(quantityId), quantityId, elementSet.ID, prefetchTime, scenarioId); // see if it's already in the buffer if (mapValueSet.containsKey(key) == true) { // it must have been fetched by someone else, so update our state prefetchMonitor.addFetchedTime(link, prefetchTime); continue; } // create a request for the next time to prefetch var valueSetRequestEntry = new ValueSetRequestEntry(webServiceManager.FindServiceIdForQuantity(quantityId), quantityId, elementSet.ID, prefetchTime, scenarioId); // attempt to insert the request immediately (non-blocking) if (queueValueSetRequest.offer(valueSetRequestEntry) == true) { traceFile.Append(string.Format("Prefetch:Requested:Link{0}/{1}:{2}", linkId, quantityId, prefetchTime)); statistics.Add("Prefetch:RequestCount", 1); // remember that this time has been prefetched prefetchMonitor.addFetchedTime(link, prefetchTime); } else { traceFile.Append(string.Format("Prefetch:RequestOfferFailed:Link{0}/{1}:{2}", linkId, quantityId, prefetchTime)); statistics.Add("Prefetch:RequestOfferFail", 1); // stop trying to prefetch if the request queue is full break; } } }