/// <summary> /// A minimally blocking call that starts a background task to update the graph. /// </summary> /// <param name="compacted"></param> /// <param name="pageUri"></param> public void Add(JObject compacted, Uri pageUri) { Debug.Assert(pageUri.AbsoluteUri.IndexOf("#") == -1, "Add should be on the full Uri and not the child Uri!"); JsonLdPage page = new JsonLdPage(pageUri, compacted); if (_pages.TryAdd(pageUri, page)) { // start the graph load page.BeginLoad(AddCallback); } else { // clean up page.Dispose(); } }
/// <summary> /// Removes all pages not used within the given time span. /// </summary> private void CleanUp(TimeSpan keepPagesUsedWithin) { DateTime cutOff = DateTime.UtcNow.Subtract(keepPagesUsedWithin); // lock to keep any new pages from being added during this lock (this) { // just in case we show really late if (_disposed) { return; } // create a working set of pages that can be considered locked JsonLdPage[] pages = _pages.Values.ToArray(); // if pages are still loading we should skip the clean up // TODO: post-preview this should force a clean up if the graph is huge if (pages.All(p => p.IsLoaded)) { // check if a clean up is needed if (pages.Any(p => !p.UsedAfter(cutOff))) { List <JsonLdPage> keep = new List <JsonLdPage>(pages.Length); List <JsonLdPage> remove = new List <JsonLdPage>(pages.Length); // pages could potentially change last accessed times, so make the decisions in one shot foreach (var page in pages) { if (page.UsedAfter(cutOff)) { keep.Add(page); } else { remove.Add(page); } } // second check to make sure we need to do this if (remove.Count > 0) { DataTraceSources.Verbose("[EntityCache] EntityCache rebuild started."); JsonLdGraph graph = new JsonLdGraph(); // graph merge foreach (var page in keep) { graph.Merge(page.Graph); } _masterGraph = graph; DataTraceSources.Verbose("[EntityCache] EntityCache rebuild complete."); // remove and dispose of the old pages foreach (var page in remove) { JsonLdPage removedPage = null; if (_pages.TryRemove(page.Uri, out removedPage)) { Debug.Assert(!removedPage.UsedAfter(cutOff), "Someone used a page that was scheduled to be removed. This should have been locked."); removedPage.Dispose(); } else { Debug.Fail(page.Uri.AbsoluteUri + " disappeared from the page cache."); } } } } } } }