?? versionedstorage.cs
字號:
using System;
using System.Collections;
using Perst;
namespace Rdf
{
/// <summary>Root class for Perst storage</summary>
public class DatabaseRoot:PersistentResource
{
/// <summary>Root object in the graph</summary>
public VersionHistory rootObject;
/// <summary>Index used to access object by URI prefix</summary>
public Index prefixUriIndex;
/// <summary>Index used to access object by URI suffix</summary>
public Index suffixUriIndex;
/// <summary>Index used to search object by string property name:value pair</summary>
public CompoundIndex strPropIndex;
/// <summary>Index used to search object by numeric property name:value pair</summary>
public CompoundIndex numPropIndex;
/// <summary>Index used to search object by datetime property name:value pair</summary>
public CompoundIndex timePropIndex;
/// <summary>Index used to search object by reference property name:value pair</summary>
public CompoundIndex refPropIndex;
/// <summary>Index used to locate property definition by property name</summary>
public FieldIndex propDefIndex;
/// <summary>Index used to perform spatial search locating overlapped rectangles</summary>
public Index inverseIndex;
/// <summary>Inverse keywords index</summary>
public SpatialIndexR2 spatialIndex;
/// <summary>Set of the latest versions</summary>
public ISet latest;
/// <summary>Timestamp index</summary>
public FieldIndex timeIndex;
/// <summary>Type of the types</summary>
public VersionHistory metatype;
}
/// <summary>Which verions of the object should be inspected</summary>
public enum SearchKind
{
/// <summary>Latest version in version history</summary>
LatestVersion,
/// <summary>All versions in version history</summary>
AllVersions,
/// <summary>Latest version before sepcified timestamp</summary>
LatestBefore,
/// <summary>Oldest version after sepcified timestamp</summary>
OldestAfter
}
/// <summary>
/// Main class
/// </summary>
public class VersionedStorage
{
Storage db;
DatabaseRoot root;
/// <summary>
/// List of separator characters used to split string into keywords
/// </summary>
public static char[] keywordSeparators =
{
' ',
','
};
/// <summary>
/// List of most commonly used words which should be ignored andnot included in inverse index
/// </summary>
public static Hashtable keywordStopList = new Hashtable();
static VersionedStorage()
{
keywordStopList["the"] = true;
keywordStopList["at"] = true;
keywordStopList["of"] = true;
keywordStopList["a"] = true;
keywordStopList["to"] = true;
keywordStopList["at"] = true;
keywordStopList["and"] = true;
keywordStopList["or"] = true;
keywordStopList["i"] = true;
}
/// <summary>Open database</summary>
/// <param name="filePath">path to the database file</param>
public void Open(string filePath)
{
db = StorageFactory.Instance.CreateStorage();
db.Open(filePath);
root = (DatabaseRoot)db.Root;
if (root == null)
{
root = new DatabaseRoot();
root.prefixUriIndex = db.CreateIndex(typeof(string), true);
root.suffixUriIndex = db.CreateIndex(typeof(string), true);
root.strPropIndex = db.CreateIndex(new Type[]{typeof(PropDef), typeof(string)}, false);
root.numPropIndex = db.CreateIndex(new Type[]{typeof(PropDef), typeof(double)}, false);
root.refPropIndex = db.CreateIndex(new Type[]{typeof(PropDef), typeof(VersionHistory)}, false);
root.timePropIndex = db.CreateIndex(new Type[]{typeof(PropDef), typeof(DateTime)}, false);
root.propDefIndex = db.CreateFieldIndex(typeof(PropDef), "name", true);
root.timeIndex = db.CreateFieldIndex(typeof(Thing), "timestamp", false);
root.inverseIndex = db.CreateIndex(typeof(string), false);
root.spatialIndex = db.CreateSpatialIndexR2();
root.latest = db.CreateSet();
CreateMetaType();
db.Root = root;
}
}
/// <summary>Get verion history by URI</summary>
/// <param name="uri">object URI</param>
/// <returns>version history or null if no such object is found</returns>
public VersionHistory GetObject(string uri)
{
return (VersionHistory)root.prefixUriIndex[uri];
}
/// <summary>Get latest verion of object with specified URI</summary>
/// <param name="uri">object URI</param>
/// <returns>latest version of object or null if no such object is found</returns>
public Thing GetLatestVersion(string uri)
{
VersionHistory vh = (VersionHistory)root.prefixUriIndex[uri];
return (vh != null) ? vh.Latest : null;
}
/// <summary>Get verion history by URI and timestamp</summary>
/// <param name="uri">object URI</param>
/// <param name="kind">search kind, should be object SearchKind.LatestVersion, SearchKind.LatestBefore or
/// SearchKind.OldestAfter</param>
/// <param name="timestamp">timestamp used to locate version</param>
/// <returns>version of the object or null if no such version is found</returns>
public Thing GetVersion(string uri, SearchKind kind, DateTime timestamp)
{
VersionHistory vh = (VersionHistory)root.prefixUriIndex[uri];
if (vh != null)
{
return vh.GetVersion(kind, timestamp);
}
return null;
}
/// <summary>Create bew object. If version history with this URI is not exists, it is created first.
/// Then new object version is created and appended to this version history.
/// </summary>
/// <param name="uri">object URI</param>
/// <param name="type">URI of object type</param>
/// <param name="props">object properties</param>
/// <returns>created object version</returns>
public Thing CreateObject(string uri, string type, NameVal[] props)
{
VersionHistory vh = (VersionHistory)root.prefixUriIndex[uri];
if (vh == null)
{
VersionHistory typeVh = null;
typeVh = GetObject(type);
if (typeVh == null)
{
typeVh = CreateVersionHistory(type, root.metatype);
CreateObject(root.metatype.Latest, typeVh, new NameVal[0]);
}
vh = CreateVersionHistory(uri, typeVh);
}
else
{
root.latest.Remove(vh.Latest);
}
return CreateObject(vh.type.Latest, vh, props);
}
/// <summary>Get iterator through object matching specified search parameters</summary>
/// <param name="type">String representing type of the object (direct or indirect - IsInstanceOf
/// method will be used to check if object belongs to the specified type). It may be null,
/// in this case type criteria is skipped.</param>
/// <param name="uri">Object URI pattern. It may be null, in this case URI is not inspected.</param>
/// <param name="patterns">array of name:value pairs specifying search condition for object properties</param>
/// <param name="kind">search kind used to select inspected versions</param>
/// <param name="timestamp">timestamp used to select versions, if kind is SearchKind.LatestVersion
/// or SearchKind.AllVersions this parameter is ignored</param>
/// <returns>Enumerator through object meet search criteria.</returns>
public IEnumerable Search(string type, string uri, NameVal[] patterns, SearchKind kind, DateTime timestamp)
{
VersionHistory typeVh = null;
root.SharedLock();
try
{
if (type != null)
{
typeVh = GetObject(type);
if (typeVh == null)
{
return new object[0]; // empty selection
}
}
if (uri != null)
{
int wc = uri.IndexOf('*');
if (wc < 0)
{
return new SearchResult(root, typeVh, null, patterns, kind, timestamp, root.prefixUriIndex.GetEnumerator(uri, uri));
}
else if (wc > 0)
{
String prefix = uri.Substring(0, wc);
return new SearchResult(root, typeVh, uri, patterns, kind, timestamp, root.prefixUriIndex.GetEnumerator(prefix));
}
else if ((wc = uri.LastIndexOf('*')) < uri.Length-1)
{
String suffix = ReverseString(uri.Substring(wc+1, uri.Length-wc-1));
return new SearchResult(root, typeVh, uri, patterns, kind, timestamp, root.suffixUriIndex.GetEnumerator(suffix));
}
}
if (patterns.Length > 0)
{
NameVal prop = patterns[0];
object val = prop.val;
NameVal[] restOfPatterns = SubArray(patterns);
switch (prop.name)
{
case Symbols.Timestamp:
if (val is Range)
{
Range range = (Range)val;
if (range.from is DateTime)
{
Key fromKey = new Key((DateTime)range.from, range.fromInclusive);
Key tillKey = new Key((DateTime)range.till, range.tillInclusive);
return new SearchResult(root, typeVh, uri, restOfPatterns, kind, timestamp,
root.timeIndex.GetEnumerator(fromKey, tillKey));
}
}
else if (val is DateTime)
{
Key key = new Key((DateTime)val);
return new SearchResult(root, typeVh, uri, restOfPatterns, kind, timestamp,
root.timeIndex.GetEnumerator(key, key));
}
return new object[0]; // empty selection
case Symbols.Rectangle:
if (val is NameVal[])
{
NameVal[] coord = (NameVal[])val;
if (coord.Length == 4)
{
RectangleR2 r = new RectangleR2((double)coord[0].val,
(double)coord[1].val,
(double)coord[2].val,
(double)coord[3].val);
return new SearchResult(root, typeVh, uri, restOfPatterns, kind, timestamp,
root.spatialIndex.Overlaps(r).GetEnumerator());
}
}
break;
case Symbols.Point:
if (val is NameVal[])
{
NameVal[] coord = (NameVal[])val;
if (coord.Length == 2)
{
double x = (double)coord[0].val;
double y = (double)coord[1].val;
RectangleR2 r = new RectangleR2(x, y, x, y);
return new SearchResult(root, typeVh, uri, restOfPatterns, kind, timestamp,
root.spatialIndex.Overlaps(r).GetEnumerator());
}
}
break;
case Symbols.Keyword:
if (val is string)
{
ArrayList keywords = new ArrayList();
foreach (string keyword in ((string)val).ToLower().Split(keywordSeparators))
{
if (keyword.Length > 0 && !keywordStopList.ContainsKey(keyword))
{
keywords.Add(keyword);
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -