// Copyright Microsoft Corporation.
// This source file is subject to the Microsoft Permissive License.
// See http://www.microsoft.com/resources/sharedsource/licensingbasics/sharedsourcelicenses.mspx.
// All other rights reserved.
using System;
using System.Collections.Generic;
using System.IO;
using System.Xml;
using System.Xml.XPath;
namespace Microsoft.Ddue.Tools{
// the storage system
internal class IndexedFileCache
{
public IndexedFileCache(string keyXPath, string valueXPath, int cacheSize)
{
valueExpression = XPathExpression.Compile(valueXPath);
keyExpression = XPathExpression.Compile(keyXPath);
_cacheSize = cacheSize;
cache = new Dictionary<string, IndexedFile>(_cacheSize);
lruLinkedList = new LinkedList<string>();
}
// search pattern for value nodes to be mapped
private XPathExpression valueExpression;
// search pattern for the key identifier (relative to the value node)
private XPathExpression keyExpression;
// an index mapping topic IDs to files
private Dictionary<string, string> idToFileMap = new Dictionary<string, string>();
public int ParseDocuments(string wildcardPath)
{
string directoryPart = Path.GetDirectoryName(wildcardPath);
if (String.IsNullOrEmpty(directoryPart)) directoryPart = Environment.CurrentDirectory;
directoryPart = Path.GetFullPath(directoryPart);
string filePart = Path.GetFileName(wildcardPath);
string[] files = Directory.GetFiles(directoryPart, filePart);
// WriteMessage(MessageLevel.Info, String.Format("Found {0} files.", files.Length) );
foreach (string file in files)
{
ParseDocument(file);
}
return (files.Length);
}
private void ParseDocument(string file)
{
try
{
XPathDocument document = new XPathDocument(file);
XPathNodeIterator valueNodes = document.CreateNavigator().Select(valueExpression);
foreach (XPathNavigator valueNode in valueNodes)
{
XPathNavigator keyNode = valueNode.SelectSingleNode(keyExpression);
if (keyNode == null) continue;
string key = keyNode.Value;
// log multiple occurences of a single id
if (idToFileMap.ContainsKey(key))
{
// WriteMessage(MessageLevel.Warn, String.Format("Entries for the key '{0}' occur in both '{1}' and '{2}'. The first entry will be used.", key, idToFileMap[key], file));
}
else
{
idToFileMap[key] = file;
}
}
}
catch (XmlException)
{
// WriteMessage(MessageLevel.Error, e.Message);
}
}
// a simple document caching mechanism
private int _cacheSize = 10;
private LinkedList<String> lruLinkedList;
private Dictionary<string, IndexedFile> cache;
private IndexedFile GetCachedDocument(string identifier)
{
string file;
if (idToFileMap.TryGetValue(identifier, out file))
{
IndexedFile document;
if (cache.TryGetValue(file, out document))
{
// move the file from its current position to the head of the lru linked list
lruLinkedList.Remove(document.ListNode);
lruLinkedList.AddFirst(document.ListNode);
}
else
{
// not in the cache, so load and index a new source file
document = new IndexedFile(file, valueExpression, keyExpression);
if (cache.Count >= _cacheSize)
{
// the cache is full
// the last node in the linked list has the path of the next file to remove from the cache
if (lruLinkedList.Last != null)
{
cache.Remove(lruLinkedList.Last.Value);
lruLinkedList.RemoveLast();
}
}
// add the new file to the cache and to the head of the lru linked list
cache.Add(file, document);
document.ListNode = lruLinkedList.AddFirst(file);
}
return (document);
}
else
{
return (null);
}
}
public XPathNavigator GetContent(string identifier)
{
// get the document containing the identifier
IndexedFile document = GetCachedDocument(identifier);
if (document == null) return (null);
// select the comment part of the document
return document.GetContent(identifier);
}
public int Count
{
get
{
return (idToFileMap.Count);
}
}
}
internal class IndexedFile
{
Dictionary<string, XPathNavigator> valueIndex = new Dictionary<string, XPathNavigator>();
public IndexedFile(string filepath, XPathExpression valueExpression, XPathExpression keyExpression)
{
XPathDocument xpDoc = new XPathDocument(filepath);
XPathNodeIterator valueNodes = xpDoc.CreateNavigator().Select(valueExpression);
foreach (XPathNavigator valueNode in valueNodes)
{
XPathNavigator keyNode = valueNode.SelectSingleNode(keyExpression);
if (keyNode == null)
continue;
string key = keyNode.Value;
if (!valueIndex.ContainsKey(key))
valueIndex.Add(key, valueNode);
}
}
public XPathNavigator GetContent(string key)
{
return valueIndex[key];
}
private LinkedListNode<string> listNode;
public LinkedListNode<string> ListNode
{
get
{
return (listNode);
}
set
{
listNode = value;
}
}
}
}
|