stsdb开发指南
摘自:http://www.iopenworks.com/Products/ProductDetails/DevelopmentGuide?proID=387
多线程问题,请参见线程安全小结
1 STSdb存储引擎
STSdb存储引擎是一个基于瀑布树结构实现的NoSQL数据库和虚拟文件系统。该存储引擎提供两种数据结构——XIndex和XFile,一个存储引擎可以包含多个XIndex表和XFile文件。下面我们看一个简单示例。
2 简单示例
(1)打开数据库,创建表
using (StorageEngine engine =newStorageEngine("stsdb4.sys","stsdb4.dat")){XIndex<int,string> table = engine.OpenXIndex<int,string>("table");for(int i =0; i <1000000; i++){
table[i]= i.ToString();} table.Flush();
engine.Commit();}
(2)打开数据库,从表中读取数据
using (StorageEngine engine =newStorageEngine("stsdb4.sys","stsdb4.dat")){XIndex<int,string> table = engine.OpenXIndex<int,string>("table");foreach(var row in table)//table.Forward(), table.Backward(){Console.WriteLine("{0} {1}", row.Key, row.Value);}}
3 XIndex
XIndex是一个按序的键/值对存储(表)。我们可以在同一个引擎使用不同的键/记录类型来读取多个普通的表。每一个表并没有列数量的特殊限制。
需要注意的是:在当前版本提交操作是在存储引擎这一级别的——engine.Commit(),它将提交对所有表的更新。在官方的Release版本,每一个表的Commit()方法也将可用。
3.1 XIndex<TKey, TRecord>泛型类支持的泛型类型
我们可以使用XIndex<TKey, TRecord> table来定义一个表。这里TKey和TRecord支持的类型有:
● 基本类型——Boolean、Char、SByte、Byte、Int16、UInt16、Int32、UInt32、Int64、UInt64、Single、Double、Decimal、DateTime、String、byte[];
● 包含默认构造器的类型和结构体,他们使用基本类型定义了公开的读/写属性。
● 包含默认构造器的类型和结构体,他们使用基本类型和上述使用基本类型定义的类/结构体定义了公开的读/写属性。
● 可以转换成IData接口的类型。
下面我们来看一个示例,我们定义了两个类型,对应于TKey和TRecord。
publicclassKey{publicstringSymbol{ get;set;}publicDateTimeTimestamp{ get;set;}}publicclassTick{publicdoubleBid{ get;set;}publicdoubleAsk{ get;set;}publiclongVolume{ get;set;}publicstringProvider{ get;set;}}
我们可以以以下方式来打开表。
XIndex<long,Tick> table1 = engine.OpenXIndex<long,Tick>("table1");XIndex<DateTime,Tick> table2 = engine.OpenXIndex<DateTime,Tick>("table2");XIndex<Key,Tick> table3 = engine.OpenXIndex<Key,Tick>("table3");
或者,甚至可以用以下方式。
XIndex<Tick,Tick> table4 = engine.OpenXIndex<Tick,Tick>("table4");
在使用组合键的情况下,存储引擎将会使用子键进行比较。
3.2 XIndex<TKey, TRecord> 类型定义的方法
XIndex<TKey,TRecord>实现了IIndex<TKey,TRecord>接口,它定义了如下的方法:
publicinterface IIndex<TKey,TRecord>:IIndex,IEnumerable<KeyValuePair<TKey,TRecord>>{TRecordthis[TKey key]{ get;set;}voidReplace(TKey key,TRecord record);voidInsertOrIgnore(TKey key,TRecord record);voidDelete(TKey key);voidDelete(TKey fromKey,TKey toKey);voidClear(); bool Exists(TKey key);
bool TryGet(TKey key,outTRecord record);TRecordFind(TKey key);TRecordTryGetOrDefault(TKey key,TRecord defaultRecord);KeyValuePair<TKey,TRecord>?FindNext(TKey key);KeyValuePair<TKey,TRecord>?FindAfter(TKey key);KeyValuePair<TKey,TRecord>?FindPrev(TKey key);KeyValuePair<TKey,TRecord>?FindBefore(TKey key);IEnumerable<KeyValuePair<TKey,TRecord>>Forward();IEnumerable<KeyValuePair<TKey,TRecord>>Forward(TKeyfrom, bool hasFrom,TKey to, bool hasTo);IEnumerable<KeyValuePair<TKey,TRecord>>Backward();IEnumerable<KeyValuePair<TKey,TRecord>>Backward(TKey to, bool hasTo,TKeyfrom, bool hasFrom);KeyValuePair<TKey,TRecord>FirstRow{ get;}KeyValuePair<TKey,TRecord>LastRow{ get;}longCount();}
默认的XIndex迭代器使用升序方式遍历了表中的每一行。
Forward()方法以升序遍历表的每一行。
Backward()方法以降序遍历表的每一行。
FindNext()返回大于等于指定Key的第一行。
FindAfter()返回大于指定Key的第一行。
FindPrev()返回小于等于指定Key的第一行。
FindBefore()返回小于指定Key的第一行。
FirstRow返回最小Key的行。
LastRow返回最大Key的行。
以下方法用于异步更改XIndex的内容,他们在瀑布树中执行相应的操作。
this[TKey key]set;Replace(TKey key,TRecord record);InsertOrIgnore(TKey key,TRecord record);Delete(TKey key);Clear().
3.3 XIndex<TKey, TRecord>基础知识
前面已经提过,每一个存储引擎可以使用不同的类型处理多个XIndex<TKey,TRecord>表。每一个TKey和TRecord可以是基本类型或者复杂结构体或者类型。然而,在所有情况,每一个泛型的XIndex都使用一个非泛型的XIndex表来存储它的数据,如下所示。
public class XIndex : IIndex<IData, IData>
当一个XIndex被创建,它使用.NET表达式自动生成和编译能够将每一个TKey和TRecord实例转换成一个合适的IData实例的转换代码。因此,从一个数据库的角度来看,XIndex<TKey, TRecord>好像是在XIndex中实现了应用层数据和内部数据的转换。这确保了内部存储的独立,而依赖于应用定义的类型,同时为以更自然的方式向开发者提供了使用自定义类型的存储。
3.4 XIndex和IData实现
XInde使用如下由STSdb实现的IData类型。
publicinterface IData{}publicclassData<TSlot0>:IData{publicTSlot0Slot0;}publicclassData<TSlot0,TSlot1>:IData{publicTSlot0Slot0;publicTSlot1Slot1;}publicclassData<TSlot0,TSlot1,TSlot2>:IData{publicTSlot0Slot0;publicTSlot1Slot1;publicTSlot2Slot2;}...
当前版本支持最多64个Slot的Key和Record的Data类型。每一个Slot可以是任何基本类型。
以下代码演示了如何直接使用非泛型XIndex。
//writing
using (StorageEngine engine =newStorageEngine("stsdb4.sys","stsdb4.dat")){XIndex table = engine.OpenXIndex(typeof(Data<int>),typeof(Data<string>),"table");for(int i =0; i <1000000; i++){
table[newData<int>(i)]=newData<string>(i.ToString());} table.Flush();
engine.Commit();}
//reading
using (StorageEngine engine =newStorageEngine("stsdb4.sys","stsdb4.dat")){XIndex table = engine.OpenXIndex(typeof(Data<int>),typeof(Data<string>),"table");foreach(var row in table)//table.Forward(), table.Backward(){Data<int> key =(Data<int>)row.Key;Data<string> record =(Data<string>)row.Value;Console.WriteLine("{0} {1}", key.Slot0, record.Slot0);}}
3.5 数据转换
数据转换用于实现将应用定义的类型与IData类型的转换。他们构建了XIndex<TKey, TRecord>和XIndex表的转换层。所有的转换都实现了如下接口。
publicinterface IDataTransformer<T>{IDataToIData(T item);
T FromIData(IData data);DataDescriptorDataDescriptor{ get;}}
每一个XIndex<TKey, TRecord>示例自动生成两个数据转换——一个用于实现Key的转换,另一个实现Record的转换。也就是说,每一个输入的TKey/TRecord实例将转换成合适的IData实例。同样的,来自于XIndex的每一个IData实例也将转换到TKey/TRecord实例(在一些很复杂的情况,可以由自己来定义转换)。
假设我们定义了以下类型。
publicclassTick{publicstringSymbol{ get;set;}publicDateTimeTimestamp{ get;set;}publicdoubleBid{ get;set;}publicdoubleAsk{ get;set;}publiclongVolume{ get;set;}publicstringProvider{ get;set;}}
并且我们定义了XIndex<long, Tick>。
XIndex<long,Tick> table = engine.OpenXIndex<long,Tick>("table");
那么,在后端的XIndex表将使用以下两个对应于键和记录的类型。
Data<long>Data<string,DateTime,double,double,long,string>
我们可以用以下代码来模拟打开后端的XIndex表。
XIndex table2 = engine.OpenXIndex(typeof(Data<long>),typeof(Data<string,DateTime,double,double,long,string>),"table");
在上述的例子,table和table2将指向相同的数据。
如果我们希望使用非基本类型来扩展Tick类,比如。
publicclassProvider{publicstringName{ get;set;}publicstringWebsite{ get;set;}}publicclassTick{publicstringSymbol{ get;set;}publicDateTimeTimestamp{ get;set;}publicdoubleBid{ get;set;}publicdoubleAsk{ get;set;}publiclongVolume{ get;set;}publicProviderProvider{ get;set;}}
那么,此时后端的XIndex可以使用以下类型来打开。
Data<long>Data<string,DateTime,double,double,long, bool,string,string>
我们还可以使用Symbol和Timestamp并使用它作为组合键。
publicclassKey{publicstringSymbol{ get;set;}publicDateTimeTimestamp{ get;set;}}publicclassProvider{publicstringName{ get;set;}publicstringWebsite{ get;set;}}publicclassTick{//public string Symbol { get; set; }//public DateTime Timestamp { get; set; }publicdoubleBid{ get;set;}publicdoubleAsk{ get;set;}publiclongVolume{ get;set;}publicProviderProvider{ get;set;}}
XIndex<Key,Tick> table = engine.OpenXIndex<Key,Tick>("table");
此时后端的XIndex可以使用以下类型来打开。
Data<string,DateTime>Data<double,double,long, bool,string,string>
需要注意的是,因为每一个数据Slot只能由基本类型来定义,因此,需要使用一个额外的Boolean Slot来指定引用类型的对象的属性是否为null。这样,我们可以拆分自定义类型。
如果一个XIndex使用了组合Key,这些Key使用了不止一个Slot,那么数据引擎将使用BigEndian按照从小到大的Slot的顺序来比较子键。
转换成IData后,用户的数据非常适合于压缩。该引擎能够为每一个XIndex类型自动生成压缩类。这些压缩类依赖于Slot的基本类型为每一个Slot使用并行垂直方法的进行压缩。因此,压缩会很快并保持很高的压缩比。默认的,XIndex<TKey,TRecord>和XIndex以压缩的方式来保存数据。
4 XFile
STSdb 4.0支持稀疏文件存储,称为XFile。我们可以基于标准的.NET流来使用XFile。
using (StorageEngine engine =newStorageEngine("stsdb4.sys","stsdb4.dat")){XFile file = engine.OpenXFile("file");Random random =newRandom();byte[] buffer =newbyte[]{1,2,3,4,5,6,7,8,9,10};for(int i =0; i <100; i++){long position = random.Next();//writes some data on random positions
file.Seek(position,SeekOrigin.Begin);
file.Write(buffer,0, buffer.Length);} file.Flush();
engine.Commit();}
XFile使用特殊的XIndex<long, byte[]>实现且提供了更为高效的稀疏文件功能。这样,在一个存储引擎里,开发人员可以组合使用XIndex表和XFile文件。
5 线程安全
存储引擎是线程安全的,在一个存储引擎中使用不同线程创建XIndex和XFile实例是线程安全的。不过,XIndex和XFile本身不是线程安全的。在同一个存储引擎,不同的线程来处理由其创建的XIndex和XFile是线程安全的。
stsdb开发指南的更多相关文章
- ASP.NET Aries 开源开发框架:开发指南(一)
前言: 上周开源了Aries开发框架后,好多朋友都Download了源码,在运行过程里,有一些共性的问题会问到. 所以本篇打算写一下简单的开发指南,照顾一下不是太看的懂源码的同学,同时也会讲解一下框架 ...
- FreeMarker模板开发指南知识点梳理
freemarker是什么? 有什么用? 怎么用? (问得好,这些都是我想知道的问题) freemarker是什么? FreeMarker 是一款 模板引擎: 即一种基于模板和要改变的数据, 并用来生 ...
- Jetty使用教程(四:21-22)—Jetty开发指南
二十一.嵌入式开发 21.1 Jetty嵌入式开发HelloWorld 本章节将提供一些教程,通过Jetty API快速开发嵌入式代码 21.1.1 下载Jetty的jar包 Jetty目前已经把所有 ...
- JVM 平台上的各种语言的开发指南
JVM 平台上的各种语言的开发指南 为什么我们需要如此多的JVM语言? 在2013年你可以有50中JVM语言的选择来用于你的下一个项目.尽管你可以说出一大打的名字,你会准备为你的下一个项目选择一种新的 ...
- iOS原生地图开发指南续——大头针与自定义标注
iOS原生地图开发指南续——大头针与自定义标注 出自:http://www.sxt.cn/info-6042-u-7372.html 在上一篇博客中http://my.oschina.net/u/23 ...
- Angularjs中文版本开发指南发布
从本人开始在写关于Angularjs的文章开始,也算是见证了Angularjs在国内慢慢的火起来,如今的Angularjs正式如日中天.想知道为什么Angularjs会这么火,请移步angularjs ...
- nodejs开发指南读后感
nodejs开发指南读后感 阅读目录 使用nodejs创建http服务器; supervisor的使用及nodejs常见的调式代码命令了解; 了解Node核心模块; ejs模板引擎 Express 理 ...
- Libgdx 开发指南——目录
本系列文档选译自libgdx github项目 wiki : https://github.com/libgdx/libgdx/wiki 由于关于Libgdx的中文文档非常稀缺,因此在这里对官方Wik ...
- jQuery MiniUI 开发指南+API组件参考手册
jQuery MiniUI 开发指南 本文档将逐步的讲解jQuery MiniUI的方方面面,从此您将踏上jQuery MiniUI的深入探索之旅. 1.Hello M ...
随机推荐
- python Requests库在处理response时的一些陷阱
python的Requests(http://docs.python-requests.org/en/latest/)库在处理http/https请求时还是比较方便的,应用也比较广泛.但其在处理res ...
- MapReduce、Hbase接口API实践
读取hdfs中文件并做处理,取出卡号,通过卡号连接hbase查询出对应客户号,写入redis,因为不用输出,所以不调用context.write方法,整个操作在一个map中便可完成 protected ...
- 51nod 1515 明辨是非 并查集 + set + 启发式合并
给n组操作,每组操作形式为x y p. 当p为1时,如果第x变量和第y个变量可以相等,则输出YES,并限制他们相等:否则输出NO,并忽略此次操作. 当p为0时,如果第x变量和第y个变量可以不相等,则输 ...
- C++中引用的本质
一般的教材上讲到引用时,都是说"引用是对象的一个别名".我认为这种定义是不清晰的,不利于初学者理解引用.至少我自己曾经被这个定义困扰了一段时间.到底什么是"别名" ...
- MRD
搜索 复制
- angularjs实现 checkbox全选、反选的思考
之前做了一周的打酱油测试,其实感觉其实测试也是上辈子折翼的天使. 好长时间没写代码,感觉好多都不会了. 感谢这周没有单休,我能看熬夜看奥运了.我能有时间出去看个电影,我能有时间出去逛个商城,我能有时间 ...
- No.015 3Sum
15. 3Sum Total Accepted: 131800 Total Submissions: 675028 Difficulty: Medium Given an array S of n i ...
- uva1587BOX
给定6个矩形的长和宽wi和hi(1≤wi,hi≤1000),判断它们能否构成长方体的6个面. 思路是首先排序,每个矩形都是x<y,就是短边x,长边y,然后对六个矩形进行二级排序,排序以后构成长方 ...
- 如何对具有端点加密功能的LINE进行取证
LINE又有新动作了,这回默认即启用了端点加密功能,强调确保传输过程的安全,且让我们来看看如何对付新版的LINE. 有启用Letter Sealing就会在昵称前多个锁头的图像. 这手机据犯嫌供称,落 ...
- vim总结
1.vim基础用法 注:该思维导图来自笔者<Linux就该这么学>读书笔记. 移动光标: 命令 描述 k 向上移动光标(移动一行) j 向下移动光标(移动一行) h 向左移动光标(移动一个 ...