Exemplo n.º 1
0
        // Called after a reset to figure out the new indexes for the selected items
        private async Task RemapSelection()
        {
            ItemIndexRangeList        oldSelection      = selection;
            ItemCacheManager <string> oldSelectionCache = selectionCache;
            ItemIndexRangeList        newSelection      = new ItemIndexRangeList();
            ItemCacheManager <string> newSelectionCache = new ItemCacheManager <string>(fetchSelectionDataCallback, 50, "newSelectionCache");

            foreach (ItemIndexRange r in oldSelection)
            {
                IReadOnlyList <StorageFile> results = null;
                int lastResultOffset = 0, lastResultsItemIndex = 0;
                for (int i = 0; i < r.Length; i++)
                {
                    int    origIndex = r.FirstIndex + i;
                    string fileid    = oldSelectionCache[origIndex];
                    bool   matched   = false;

                    // Optimization to be able to work in batches. Once we get a batch of files from the filesystem we use that to hunt
                    // for matches rather than having to go ask for the index of each file
                    if (results != null)
                    {
                        for (int j = lastResultOffset + 1; j < results.Count; j++)
                        {
                            if (results[j].FolderRelativeId == fileid)
                            {
                                lastResultOffset = j;
                                int itemIndex = lastResultsItemIndex + j;
                                newSelection.Add((uint)itemIndex, 1);
                                newSelectionCache[itemIndex] = oldSelectionCache[origIndex];
                                matched = true;
                                break;
                            }
                        }
                    }
                    if (!matched)
                    {
                        // Get a starting point for the index of the file
                        lastResultsItemIndex = (int)(await _queryResult.FindStartIndexAsync(fileid.Substring(fileid.LastIndexOf('\\') + 1)));
                        lastResultOffset     = 0;
                        // Get the files at that point and see if the keys actually match
                        results = await _queryResult.GetFilesAsync((uint)lastResultsItemIndex, 50);

                        if (results[lastResultOffset].FolderRelativeId == fileid)
                        {
                            newSelection.Add((uint)lastResultsItemIndex, 1);
                            newSelectionCache[lastResultsItemIndex] = oldSelectionCache[origIndex];
                        }
                        else
                        {
                            // We can't find the item, so its no longer part of the selection
                        }
                    }
                }
            }
            // Update the fields for the new selection
            selection      = newSelection;
            selectionCache = newSelectionCache;
        }
Exemplo n.º 2
0
        public ItemCacheManager(fetchDataCallbackHandler callback, int batchsize = 50, string debugName = "ItemCacheManager")
        {
            cacheBlocks       = new List <CacheEntryBlock <T> >();
            requests          = new ItemIndexRangeList();
            cachedResults     = new ItemIndexRangeList();
            fetchDataCallback = callback;
            maxBatchFetchSize = batchsize;
            //set up a timer that is used to delay fetching data so that we can catch up if the list is scrolling fast
            timer       = new Windows.UI.Xaml.DispatcherTimer();
            timer.Tick += (sender, args) =>
            {
                fetchData();
            };
            timer.Interval = new TimeSpan(20 * 10000);

#if DEBUG
            this.debugName = debugName;
#endif
#if TRACE_DATASOURCE
            Debug.WriteLine(debugName + "* Cache initialized/reset");
#endif
        }
Exemplo n.º 3
0
        /// <summary>
        /// Updates the desired item range of the cache, discarding items that are not needed, and figuring out which items need to be requested. It will then kick off a fetch if required.
        /// </summary>
        /// <param name="ranges">New set of ranges the cache should hold</param>
        public void UpdateRanges(ItemIndexRange[] ranges)
        {
            //Normalize ranges to get a unique set of discontinuous ranges
            ranges = NormalizeRanges(ranges);

            // Fail fast if the ranges haven't changed
            if (!HasRangesChanged(ranges))
            {
                return;
            }

            //To make the cache update easier, we'll create a new set of CacheEntryBlocks
            List <CacheEntryBlock <T> > newCacheBlocks = new List <CacheEntryBlock <T> >();

            foreach (ItemIndexRange range in ranges)
            {
                CacheEntryBlock <T> newBlock = new CacheEntryBlock <T>()
                {
                    FirstIndex = range.FirstIndex, Length = range.Length, Items = new T[range.Length]
                };
                newCacheBlocks.Add(newBlock);
            }

#if TRACE_DATASOURCE
            string s = "┌ " + debugName + ".UpdateRanges: ";
            foreach (ItemIndexRange range in ranges)
            {
                s += range.FirstIndex + "->" + range.LastIndex + " ";
            }
            Debug.WriteLine(s);
#endif
            //Copy over data to the new cache blocks from the old ones where there is overlap
            int lastTransferred = 0;
            for (int i = 0; i < ranges.Length; i++)
            {
                CacheEntryBlock <T> newBlock = newCacheBlocks[i];
                ItemIndexRange      range    = ranges[i];
                int j = lastTransferred;
                while (j < this.cacheBlocks.Count && this.cacheBlocks[j].FirstIndex <= ranges[i].LastIndex)
                {
                    ItemIndexRange      overlap, oldEntryRange;
                    ItemIndexRange[]    added, removed;
                    CacheEntryBlock <T> oldBlock = this.cacheBlocks[j];
                    oldEntryRange = new ItemIndexRange(oldBlock.FirstIndex, oldBlock.Length);
                    bool hasOverlap = oldEntryRange.DiffRanges(range, out overlap, out removed, out added);
                    if (hasOverlap)
                    {
                        Array.Copy(oldBlock.Items, overlap.FirstIndex - oldBlock.FirstIndex, newBlock.Items, overlap.FirstIndex - range.FirstIndex, (int)overlap.Length);
#if TRACE_DATASOURCE
                        Debug.WriteLine("│ Transfering cache items " + overlap.FirstIndex + "->" + overlap.LastIndex);
#endif
                    }
                    j++;
                    if (ranges.Length > i + 1 && oldBlock.lastIndex < ranges[i + 1].FirstIndex)
                    {
                        lastTransferred = j;
                    }
                }
            }
            //swap over to the new cache
            this.cacheBlocks = newCacheBlocks;

            //figure out what items need to be fetched because we don't have them in the cache
            this.requests = new ItemIndexRangeList(ranges);
            ItemIndexRangeList newCachedResults = new ItemIndexRangeList();

            // Use the previous knowlege of what we have cached to form the new list
            foreach (ItemIndexRange range in ranges)
            {
                foreach (ItemIndexRange cached in this.cachedResults)
                {
                    ItemIndexRange   overlap;
                    ItemIndexRange[] added, removed;
                    bool             hasOverlap = cached.DiffRanges(range, out overlap, out removed, out added);
                    if (hasOverlap)
                    {
                        newCachedResults.Add(overlap);
                    }
                }
            }
            // remove the data we know we have cached from the results
            foreach (ItemIndexRange range in newCachedResults)
            {
                this.requests.Subtract(range);
            }
            this.cachedResults = newCachedResults;

            startFetchData();

#if TRACE_DATASOURCE
            s = "└ Pending requests: ";
            foreach (ItemIndexRange range in this.requests)
            {
                s += range.FirstIndex + "->" + range.LastIndex + " ";
            }
            Debug.WriteLine(s);
#endif
        }