Berkeley DB 发布新版本
Berkeley DB 4.8 新特性
经过了一年多的辛勤工作和汗水,Berkeley DB 4.8版(以下简称为DB 4.8 或者 4.8)终于发布了。下文我将概括介绍这一版本带来的一些新的特性和提升,我想 读完后您有理由相信这又会是一个激动人心的新版本。当然,具体技术细节及文 档,请参照我们的官方网站的信息(此博客的侧边栏有链接)。同时,我在此也感 谢您的关注和支持。记得留下脚印哦。
下面我就对照Berkeley DB 4.8的change log中的新特性一节来概括介绍一下。
1. B树的共享栓
所谓栓,是指一种资源,类似于mutex,是一种轻量级的锁。在4.7中,访问一个页 的数据时,需要先锁住页(page),访问完后再释放锁。而在4.8 中,我们提出了的 共享栓的概念,即当多个线程/进程并发访问同一个页的时候,尽量彼此使用共享 的栓,从而避免等待。从我们的在Solaris 10上测试结果来看,如果线程数 >= CPU数,4.7的性能下降较多;而使用的共享栓的4.8,速度比同样情况下4.7的提升 25%-16倍左右。当然,具体性能提升指标取决于应用场景和平台。
2. 提供了C# API
现在,做.net开发的用户,可以通过调用4.8的C# API 来使用Berkeley DB了。C# API 运行于Windows 32位和64位平台,要求有.net framework 2.0及以上版本。 4.8发布版本还附带了很多C#的示例和测试程序,可供广大使用者参考。具体详 情,可以关注BDB中国开发团队的Emily的博客。
3. 基于BDB 实现了C++ 中STL(集合)的功能
我想,几乎每个C++的用户都对STL中的易用性留有印象。而BDB本身又是一个 Key/Value的数据库,非常类似于集合中的 Map,那么能不能给予BDB来实现一些集 合的功能呢?BDB中国开发团队的David在过去一年中,在BDB的C++ API之上实现了 一套STL的接口。简言之,David把BDB包装成了Map, Set, Vector给开发者使用。 好处是,你的应用程序可以利用BDB提供的本地的持久化,事务,并发,错误恢复 等功能,而且性能又得以保证。也许有人会问,我直接使用C++ STL就够了,为什 么还要这么麻烦?试想,当你的应用程序的数据集很大,超出了你可用的内存的时 候,你还能用C++ 的STL吗?并发访问性能如何?如何提供事务的ACID?够了,我 想足够说服北京奥运在线售票系统开发的那帮家伙了吧?你不想你的商业应用,因 为同时在线订票的客户太多而导致系统下线吧?开个玩笑,跑题了…
4. 自动分区
我想做DBA的,尤其是Oracle DBA很多都熟悉分区。我们以关系数据库来举例说 明,假设有一张表,记录了全国13亿人的信息。平均每个人的信息量为100 kb (算 上数码照片),那么一共需要多大的磁盘空间?13亿 * 100 kb ~= 130 Terra bytes. 啥概念?约需要130个,每个容量为1T字节的硬盘。所以,我可以把这张表 分区 – 比如:姓张的存在第一个磁盘,姓李的放在第二个磁盘,… 当然,具体 分区的规则有很多,你可能根据你的应用来做相应调整。在BDB里面,可以通过DB ->set_partition(), DB->set_partition_dirs() 和 DB_ENV->add_data_dir()等 API来实现分区的目的。
5. 批量插入和批量删除
众所周知,通过BDB API读取记录时,可以每次读一条也可以批量读取。在4.8里, 我们又提供了批量插入和删除的功能,从而来提高效率。批量查询可以通过设置DB_MULTIPLE or DB_MULTIPLE_KEY in DBC->get 来实现;而在DB->put() & DB->del() 中加上 DB_MULTIPLE 和 DB_MULTIPLE_KEY 标志来实现批量插入和删除。具体性能提升指 标取决于应用场景和平台。
6. B树索引的压缩
通过对基于B树的索引进行压缩,可以达到减少索引占有的空间大小,进而减少IO 次数来提高性能。具体使用为:在DB->set_compress () 指定压缩/解压缩的 callback 函数。
7. 增加了DB_SQL的工具
4.8提供了一个新的工具,叫DB_SQL,意即它将用户的SQL DDL转换成具体的BDB的 API调用。这样,对于SQL开发者而言,他们只需用提供SQL DDL的脚本,而后通过 运行DB_SQL就可以生成具体的BDB的代码。听上去有点像关系型数据库的SQL解析, 对吗?具体细节,大家可以关注Emily 的后续博客中的介绍。
8. 集群功能的增强
在早期版本中,当多个进程需要访问Master的Environment时,必须要通过BASE API来访问。现在,在Master节点上,可以通过Replication Manager来提供多进程 共享访问Master Environment了。
9. 增加了多个database间外键的约束
同关系型数据库中,在多个表之间建立外键约束一样,DB现在也支持在多个 database之间通过建立外键实现参照完整性约束。举例来讲,有雇员表(在 DB 中,称为employee database)和部门表(DB中叫department database),它们通 过部门编号字段来建立外键。对照于DB,您可以调用DB->associate_foreign()来 建立雇员表到部门表的外键约束。通过它(外键)就可以保证:1)向雇员表中插 入记录时,每个员工的部门编号都在部门表中;2)当删除某个部门时(从部门表 删除),该部门对应的员工的部门号字段都会做自动调整:DB_ABORT, DB_CASCADE 和 DB_NULLIFY 来指定。
10. 对DB_REGISTER & DB_ENV->failchk()的增强
具体请参考发布版的文档。
11. 100% 在内存中的集群(replication)
对于HA(High Available,高可用)的应用而言,现在4.8提供了更多的持久化方 案。你可以选择基于磁盘的持久化,100%在内存的持久化以及前面二者的混合方 案。具体可通过DB_ENV->rep_set_config()中指定DB_REP_CONF_INMEM来实现。好 处是显而易见的,潜在的风险是对于Master die后的election和事务回退的风险更高。
12. 两个游标等值比较
两个游标等值比较增加了判断两个cursor是 否指向同一个数据库中的同一个key/data pair的API: DBC->cmp
Charles,
Great works! Congrats to your team.
-Eric
@gengmao
Hey, man. How could find this site! Thanks and all the best.
那个dbstl似乎没有经过严格的测试,稍微复杂一点的结构都会出错,不管是不是stl标准结构。例如以下的程序
#include “stdafx.h”
#include “berkeleydb4.8_dbvector_test.h”
#include
#include “dbstl_vector.h”
#include
#include
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// 唯一的应用程序对象
//CWinApp theApp;
using namespace std;
using namespace dbstl;
struct teststruct
{
int a;
float b;
char* c;
vector vectord;
teststruct():a(9),b(19),c(“kevin.lin”)
{
vectord.push_back(“vec1″);
vectord.push_back(“vec2″);
vectord.push_back(“vec3″);
}
};
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
int nRetCode = 0;
// 初始化 MFC 并在失败时显示错误
if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
{
// TODO: 更改错误代码以符合您的需要
_tprintf(_T(“错误: MFC 初始化失败\n”));
nRetCode = 1;
}
else
{
// TODO: 在此处为应用程序的行为编写代码。
dbstl_startup();
/*
DbEnv *penv;
penv = new DbEnv(DB_CXX_NO_EXCEPTIONS);
penv->log_set_config(DB_LOG_IN_MEMORY, 1);
penv->set_lg_bsize(128 * 1024 * 1024);
BDBOP(penv->open(“dbenv”, DB_CREATE | DB_INIT_MPOOL | DB_PRIVATE |DB_THREAD, 0777), ret);
register_db_env(penv);
*/
DbEnv *penv = dbstl::open_env(“dbenv”, 0, DB_CREATE | DB_INIT_MPOOL | DB_PRIVATE | DB_THREAD);
Db* pDb = dbstl::open_db(penv,”vectortable”,DB_RECNO,DB_CREATE |DB_THREAD, DB_RENUMBER);
Db* pDb1 = dbstl::open_db(penv,”vectorCString”,DB_RECNO,DB_CREATE |DB_THREAD, DB_RENUMBER);
Db* pDb2 = dbstl::open_db(penv,”vectorstruct”,DB_RECNO,DB_CREATE |DB_THREAD, DB_RENUMBER);
db_vector<int,ElementHolder> testvector(pDb,penv);
testvector.clear();
testvector.resize(100);
for(int i=0;i<100;++i)
{
testvector[i] = i;
}
for(db_vector<int,ElementHolder>::iterator it = testvector.begin();it!=testvector.end();++it)
{
printf(“%d\r\n”,int(*it));
}
for(unsigned int i=0;i<testvector.size();++i)
{
printf(“%d\r\n”,int(testvector[i]));
}
db_vector CStringVector(pDb1,penv);
CStringVector.clear();
CStringVector.push_back(“kevin”);
CStringVector.push_back(“Lin”);
for(unsigned int i=0;i<CStringVector.size();++i)
{
printf(“%s\r\n”,CStringVector[i].c_str());
}
db_vector StructVector(pDb2,penv);
StructVector.clear();
StructVector.push_back(teststruct());
StructVector.push_back(teststruct());
StructVector.push_back(teststruct());
for(unsigned int i=0;i<StructVector.size();++i)
{
printf(“%d,%f,%s\r\n”,StructVector[i].a,StructVector[i].b,StructVector[i].c);
for(unsigned int j=0;j<StructVector[i].vectord.size();++j)
{
printf(“[%d] = %s\r\n”,j,(int)StructVector[i].vectord[j].c_str());
}
}
dbstl::close_db(pDb);
dbstl::close_db(pDb1);
dbstl::close_db(pDb2);
dbstl::close_db_env(penv);
dbstl_exit();
}
return nRetCode;
}
这个dbstl会火!非常棒的创意,感谢开发团队的工作。但是,希望尽快改进!
尊敬的开发组:
非stl结构不支持尚可接受,但是标准的stl结构也不支持就不太好用了。后来思考了一下,是不是这个dbstl有一些限制没有公布?比如说象原始的berkeleydb那样不支持结构里带有指针类型?带有指针的数据结构一定要转化成数据流才存储吗? 希望给个提示! 谢谢!
不错 很强大,偶试着耍下
非常奇怪的是,除了那几个简陋的例子之外,到处都找不到dbstl的资料,好像全世界就只有我关心似的!这么好用的东西没有人关注太可惜了,不过这也是开源软件的软肋!,从试用到现在,我已经花了一个整天的时间在这个无畏的问题上面了。可以说,用开源软件有时候很无奈!我只是想找一个说法,到底dbstl支不支持结构里包含结构(自定义结构里只支持包含stl结构也行),如果支持的话,那肯定是还有什么机关我不知道。如果不支持的话,我准备自己写一个berkeleydb 的dbstl(用流的方式来存储)。现在 开工的话怕万一支持的话岂不是浪费时间!请给我一个答案吧。
谢谢,我会帮助你使用dbstl的
@davidzhao
怎么帮助啊?是不是要交钱才能有帮助啊?
这个teststruct当中,有一个字符串,以及一个字符串的数组。这样的话,一个teststruct类型的实例不是在一个连续的内存块当中的,所以,你需要为它注册一个marshal和unmarshal的回调函数,dbstl API 才能正确地为你存储和恢复对象。具体请看这个文档:http://www.oracle.com/technology/documentation/berkeley-db/db/programmer_reference/stl_complex_rw.html
另外,db_vector CStringVector(pDb1,penv); 和 db_vector StructVector(pDb2,penv); 这两行是错误的,因为你没有给模板传入类型参数。
如上个回复所述,你需要查看这个文档: http://www.oracle.com/technology/documentation/berkeley-db/db/programmer_reference/stl_complex_rw.html
dbstl是Berkeley DB 4.8的新的API, 在 Berkeley DB 4.8发布之前, 全世界只有我们组内知道它的存在,所以你暂时不会搜索到任何关于它的信息的。不过,相信随着大家的使用和我们的改进,会有越来越多的人使用和贡献自己的经验的。
非常感谢你的使用、意见和建议,如果你看了我的前几个回复后,还有困难,请继续在这里提问,或者到 Oracle Technology Network 的Berkeley DB版提问。另外,我的经验是,尽快学会使用一个库的最好的办法,是看一下它的示例程序和测试包。在你的Berkeley DB代码根目录里面的 test_stl/base里面,有关于dbstl的所有功能的测试代码,相信你会从中找到使用某种功能的示例代码。
另外, http://www.oracle.com/technology/documentation/berkeley-db/db/programmer_reference/stl.html 这一章分节讲解了dbstl的各种功能的用法;
这个 http://www.oracle.com/technology/documentation/berkeley-db/db/api_reference/STL/frame_main.html 是dbstl API 文档的链接,用于查找某个类或者函数的具体用法。
相信在示例、测试代码和文档的帮助下,你会更容易的学会使用它。同时,我们也会更多地关注bdbchina上面大家遇到的问题,尽快帮助解决!
谢谢!
再补充一下: dbstl是支持你的测试中那个teststruct类型的,不过,由于那个类型的实例不是分布在一个连续的内存块当中的,所以你需要为那个类型注册回调函数来marshal和unmarshal一个teststruct类型的实例。 这就是所谓的“机关”,呵呵。 其实在 http://www.oracle.com/technology/documentation/berkeley-db/db/programmer_reference/stl_complex_rw.html 当中讲到了。
另外,你需要使用的类DsbtlElemTraits的文档http://www.oracle.com/technology/documentation/berkeley-db/db/api_reference/STL/DbstlElemTraits.html 中也详细地讲述了这点。
@davidzhao
太感谢您的无私帮助了!不知道您写这套库用了多少时间?
稍微看了一下,感觉有点繁琐,如果仿照mfc里的CArchive做一个DBArchive,然后要求用户在自定义类里重载
class::serialize(DBArchive& ar,T& data)
{
if(DBArchive.isStore())
{
ar<<data.a<<data.b<>data.a>>data.b>>…;
}
}
会不会更好一点? 我原来就是这个思路做了一套函数库来用,但是非常遗憾的是没有想到用STL这么方便的接口来设计,您这个创意太厉害了,跟berkeleydb简直是绝配!在您这套库出来后,如果我再设计一个就未免有重复造轮子之嫌,而且工作量不小!放弃了!
您的评论需要等待管理员审核通过.
稍微看了一下,感觉有点繁琐,如果仿照mfc里的CArchive做一个DBArchive,然后要求用户在自定义类里重载
class::serialize(DBArchive& ar,T& data)
{
if(DBArchive.isStore())
{
ar<<data.a<>data.a>>data.b>>…;
}
}
会不会更好一点? 我原来就是这个思路做了一套函数库来用,但是非常遗憾的是没有想到用STL这么方便的接口来设计,您这个创意太厉害了,跟berkeleydb简直是绝配!在您这套库出来后,如果我再设计一个就未免有重复造轮子之嫌,而且工作量不小!放弃了!
@林林
Hi 林林,
为了方便我们和你自己,如果你有时间和兴趣,我希望你仔细研究一下BDB STL,然后有不懂的问题再来问。实际上,你的好多问题,通过阅读文档都是可以找到答案的,难道不是吗?
你”稍微”看了一下,对我们的工作成果有点不尊重吧?
@chaohuang
我没有任何轻视你们工作的意思,如果我的任何语言让你们有这种感觉,是我的不是,我表示道歉!
不过对于含有指针的自定义结构的存储,你们的例子隐藏得太深了,也难怪我没找到。竟然是用平常很少用到的变长结构体作为例子。里面还夹杂了不少跟主题无关的程序逻辑。而我找例题的时候,当看到char类型,就略过去了,压根就没想到是在这里,太久没用到变长结构体了,不好意思。
能不能再奉献一个更纯粹一点的例子啊?
比如一个struct teststruct { vector strvec;
vector intvec;};
然后我就想看看怎么存储与读出就可以了。就是不知道你们在百忙之中有没有时间抽空写一个?作为回报,我将写一篇有关dbstl的详细的介绍放到csdn上。不知道你们接不接受?
是
struct teststruct
{
vector《std::string》 stringvec;
vector 《int》 intvec;
};
@林林
谢谢。欢迎你写BDB的文章(DBSTL 或者非DBSTL都行)。你可以和David多沟通(比如你推荐的STL的例子),他是BDB STL的作者。
@davidzhao
db_vector testvector(pDb,penv);
这句在我的程序里没错,只不过粘帖上来的时候不知道为什么一些字符串被你们的网站给吃掉了.特别是《 中间字符串 》这种格式的文字,特别容易丢失。
@chaohuang
呵呵,dbstl我是真有兴趣写。至于berkeleydb的普通api就不必了吧,网上的例题比比皆是,我再写也写不出朵花来。这个dbstl可就不一样了。说不定是第一家分号。
@林林
你可以投稿程序员杂志。投稿以前,我们也可以帮你review你的文章。
如果你文章能被录用,我们还可以给你提供一个小U盘做奖品。
~~~~我是不是第一听众呢。哈哈哈哈
@xinguozhong
强烈建议修改自定义结构存储接口,现在的接口完全牺牲了stl接口的方便性。而在c++里,自定义结构通常不会包含简单指针,而是动态结构类象vector,map等。
在这里我奉上我以前为berkeley 4.2写的接口里的针对自定义结构存储的一个辅助类,水平有限,献丑了。从技术上来说是超级简单,但从用户体验来说,使用起来非常的愉悦。
(注意:你们的网站会吞字符,只能看个大慨了)
#pragma once
#include
//注意:如果是自定义类或结构的话,要重载void Serialize(CDbArchive& stream);
class CDbArchive
{
public:
CDbArchive(void):pBuffer(NULL),BufferSize(0),_IsStore(false){}
~CDbArchive(void){ if(pBuffer) free(pBuffer); }
private:
unsigned int BufferSize;
char* pBuffer;
bool _IsStore;
private:
template
void In_PrimitiveStream(T PrimitiveData); //简单类型数据的流
template
void Out_PrimitiveStream(T& PrimitiveData); //简单类型数据的流
public:
unsigned int GetSize(void) { return BufferSize;}
char* GetBuffer(void) { return pBuffer;}
bool IsStore(void) { return _IsStore;}
void Clear(void){ if(pBuffer) free(pBuffer); pBuffer = NULL; BufferSize = 0;}
public:
CDbArchive& operator << (char Data);
CDbArchive& operator << (unsigned char Data);
CDbArchive& operator << (wchar_t Data);
CDbArchive& operator << (short Data);
CDbArchive& operator << (unsigned short Data);
CDbArchive& operator << (int Data);
CDbArchive& operator << (unsigned int Data);
CDbArchive& operator << (long Data);
CDbArchive& operator << (unsigned long Data);
CDbArchive& operator << (long long Data);
CDbArchive& operator << (unsigned long long Data);
CDbArchive& operator << (float Data);
CDbArchive& operator << (double Data);
CDbArchive& operator << (bool Data);
CDbArchive& operator << (CString Data);
template
CDbArchive& operator <> (char& Data);
CDbArchive& operator >> (unsigned char& Data);
CDbArchive& operator >> (wchar_t& Data);
CDbArchive& operator >> (short& Data);
CDbArchive& operator >> (unsigned short& Data);
CDbArchive& operator >> (int& Data);
CDbArchive& operator >> (unsigned int& Data);
CDbArchive& operator >> (long& Data);
CDbArchive& operator >> (unsigned long& Data);
CDbArchive& operator >> (long long Data);
CDbArchive& operator >> (unsigned long long Data);
CDbArchive& operator >> (float& Data);
CDbArchive& operator >> (double& Data);
CDbArchive& operator >> (bool& Data);
CDbArchive& operator >> (CString& String);
template
CDbArchive& operator >> (T& Data); //注意:如果运行到这里,一定是类或结构体,否则就是我漏掉了某个基本类型
//如果是类或结构体,需要用户重载void Serialize(CDbArchive&)函数
};
template void CDbArchive::In_PrimitiveStream(T PrimitiveData)
{
pBuffer = (char*)realloc(pBuffer,BufferSize+sizeof(T));
*(T*)(pBuffer+BufferSize) = PrimitiveData;
BufferSize += sizeof(T);
}
template void CDbArchive::Out_PrimitiveStream(T& PrimitiveData)
{
assert(BufferSize>0&&pBuffer);
PrimitiveData = *(T*)(pBuffer+BufferSize-sizeof(T));
BufferSize -= sizeof(T);
}
CDbArchive& CDbArchive::operator << (char Data)
{
In_PrimitiveStream(Data);
return *this;
}
CDbArchive& CDbArchive::operator << (unsigned char Data)
{
In_PrimitiveStream(Data);
return *this;
}
CDbArchive& CDbArchive::operator << (wchar_t Data)
{
In_PrimitiveStream(Data);
return *this;
}
CDbArchive& CDbArchive::operator << (short Data)
{
In_PrimitiveStream(Data);
return *this;
}
CDbArchive& CDbArchive::operator << (unsigned short Data)
{
In_PrimitiveStream(Data);
return *this;
}
CDbArchive& CDbArchive::operator << (int Data)
{
In_PrimitiveStream(Data);
return *this;
}
CDbArchive& CDbArchive::operator << (unsigned int Data)
{
In_PrimitiveStream(Data);
return *this;
}
CDbArchive& CDbArchive::operator << (long Data)
{
In_PrimitiveStream(Data);
return *this;
}
CDbArchive& CDbArchive::operator << (unsigned long Data)
{
In_PrimitiveStream(Data);
return *this;
}
CDbArchive& CDbArchive::operator << (long long Data)
{
In_PrimitiveStream(Data);
return *this;
}
CDbArchive& CDbArchive::operator << (unsigned long long Data)
{
In_PrimitiveStream(Data);
return *this;
}
CDbArchive& CDbArchive::operator << (float Data)
{
In_PrimitiveStream(Data);
return *this;
}
CDbArchive& CDbArchive::operator << (double Data)
{
In_PrimitiveStream(Data);
return *this;
}
CDbArchive& CDbArchive::operator << (bool Data)
{
In_PrimitiveStream(Data);
return *this;
}
CDbArchive& CDbArchive::operator << (CString String)
{
int len = String.GetLength()+1;
int size = (String.GetLength()+1)*sizeof(TCHAR);
pBuffer = (char*)realloc(pBuffer,BufferSize+size+sizeof(int));
_tcscpy_s((TCHAR*)(pBuffer+BufferSize),len,String.GetBuffer());
String.ReleaseBuffer();
BufferSize+=size;
*this<<size;
return *this;
}
template CDbArchive& CDbArchive::operator <> (char& Data)
{
Out_PrimitiveStream(Data);
return *this;
}
CDbArchive& CDbArchive::operator >> (unsigned char& Data)
{
Out_PrimitiveStream(Data);
return *this;
}
CDbArchive& CDbArchive::operator >> (wchar_t& Data)
{
Out_PrimitiveStream(Data);
return *this;
}
CDbArchive& CDbArchive::operator >> (short& Data)
{
Out_PrimitiveStream(Data);
return *this;
}
CDbArchive& CDbArchive::operator >> (unsigned short& Data)
{
Out_PrimitiveStream(Data);
return *this;
}
CDbArchive& CDbArchive::operator >> (int& Data)
{
Out_PrimitiveStream(Data);
return *this;
}
CDbArchive& CDbArchive::operator >> (unsigned int& Data)
{
Out_PrimitiveStream(Data);
return *this;
}
CDbArchive& CDbArchive::operator >> (long& Data)
{
Out_PrimitiveStream(Data);
return *this;
}
CDbArchive& CDbArchive::operator >> (unsigned long& Data)
{
Out_PrimitiveStream(Data);
return *this;
}
CDbArchive& CDbArchive::operator >> (long long Data)
{
Out_PrimitiveStream(Data);
return *this;
}
CDbArchive& CDbArchive::operator >> (unsigned long long Data)
{
Out_PrimitiveStream(Data);
return *this;
}
CDbArchive& CDbArchive::operator >> (float& Data)
{
Out_PrimitiveStream(Data);
return *this;
}
CDbArchive& CDbArchive::operator >> (double& Data)
{
Out_PrimitiveStream(Data);
return *this;
}
CDbArchive& CDbArchive::operator >> (bool& Data)
{
Out_PrimitiveStream(Data);
return *this;
}
CDbArchive& CDbArchive::operator >> (CString& String)
{
assert(BufferSize>0&&pBuffer);
int size;
*this>>size;
TCHAR* pStr = (TCHAR*)(pBuffer+BufferSize-size);
String = pStr;
BufferSize -= size;
return *this;
}
template CDbArchive& CDbArchive::operator >> (T& Data)
{
_IsStore = false;
Data.Serialize(*this);
return *this;
}
用户调用:
class testclassstream
{
public:
int a;
float b;
double c;
unsigned long d;
time_t m_time;
CString str;
public:
testclassstream():a(0),b(0),c(0),d(0),str(_T(“”)){}
testclassstream(int _a,float _b,double _c,unsigned long _d,CString _str):a(_a),b(_b),c(_c),d(_d),str(_str){}
void Serialize(CDbArchive& Stream)
{
if(Stream.IsStore())
{
Stream<<a<<b<<c<<d<<m_time<>str>>m_time>>d>>c>>b>>a;
}
}
};
testclassstream sa;
CDbArchive sStream;
sa.a = 999;
sa.str = _T(“厦门中医院”);
sStream<>sb;
这个CArchive类完全可以再加上对vector,map等的支持
其实扩展这个dbstl,使之能支持动态结构还是比较简单的,结构设计得比较合理。修改的关键在于那个DataItem类。遗憾的是这个类不支持虚函数,强行重载很危险。不然重载这个DataItem类里的一两个函数就可以了。特别是那个make_dbt
而且看了里面的set_dbt的实现,里面直接调用了memcpy,这是不是意味着当key含有指针类型的时候会有问题?
还有ElementRef
@林林
十一长假将至,好多同事都提前休假了。我们要晚点答复你了,忘你理解。也祝你有个开心的假期。
我现在的dbstl已经可以完美的支持任何的struct,class,只要在自定义的类里重载serialize()函数。不管里面包含任何的数据结构,包括vector,list,map,multimap,std::string,CString都支持!甚至是自定义结构!
经过初步的测试,db_vector,db_map,db_multimap,db_list都运行良好!
甚至db_map里的key都支持复杂结构,哈,太完美了。而且改动非常小,只改动了Data_Item里的一小小部分代码就可以了。
不过我只是粗糙的修改,不知道有什么后遗症,衷心希望dbstl原作者亲自出马,我愿意奉献我修改后的代码
早上说得太快了,经过了一个下午的认真测试确定db_vector,db_map,db_multimap都没有问题,至于db_set,出了点小问题,经过对dbstl_set.h里的class _DB_STL_set_value 类做了点小小的修改后,也运行良好!
以下是我的一些截取出来的测试代码片段
struct teststructtest
{
vector vectord;
teststructtest()
{
vectord.push_back(99);
vectord.push_back(88);
vectord.push_back(77);
}
CDbArchive& Serialize(CDbArchive& Stream)
{
if(Stream.IsStore())
{
Stream<>vectord;
}
return Stream;
}
};
db_vector StructVectortest(pDbVectorStruct,penv);
printf(“[%d] = %d\r\n”,i,(int)StructVectortest[i].vectord[j]);
db_map maptest(pDbMap,penv);
maptest[CString("lin")] = teststructtest();
wcout<<’['<first<<']‘<second.vectord[j])<<endl;
db_multimap multimaptest(pDbMultiMap,penv);
wcout<<’['<first<<']‘<second.vectord[j])<<endl;
db_set settest(pDbSet,penv);
for(db_set::iterator it = settest.begin();
wcout<<_T(“settest”)<<’['<<(wchar_t*)(LPCTSTR)*it<<']‘<<endl;
db_multiset multisettest(pDbMultiSet,penv);
multisettest.insert(CString(_T(“kevin”)));
wcout<<_T(“settest”)<<’['<<(wchar_t*)(LPCTSTR)*it<<']‘<<endl;
经过测试,存取数据完全没有问题
少贴了一行代码:StructVectortest.push_back(teststructtest());
請問一下, 版本 4.8.24 能夠在mingw上編譯成功嗎?
我今天早上試了一下, 無法正常編譯成功, 能否解決呢?
我先前使用的Berkeley DB版本 4.7.25 是能夠在mingw下編譯成功的!
1. cd build_unix
2. ../dist/configure –enable-mingw LIBCSO_LIBS=-lwsock32 LIBXSO_LIBS=-lwsock32
or
../dist/configure –enable-mingw
3. make
第2.步驟看似都通過, 但都會在第3.步驟出錯!
有一個repmgr.h的error(socklen_t), 將該行註銷則會在後面的編譯過程
出現其他錯誤.
希望有人能解答!
@林林
谢谢林林。你能整理一下你的程序,然后发给David吗(David.zhao @ ***)? 你可以动手写那个DBSTL的文章了,顺便也发给David。:-)
当然可以啊,不过没有他的邀请,我担心我的邮件他连看都不会看.
如果能够在qq上跟他交流一下就会比较快,也可以节省他的宝贵时间。我的qq号147340642。mail: 147340642@qq.com
阿隆,你好。
我们在发布4.8之前有工程师专门在MinGW上验证编译的。 我在本机试了一下, 也可以顺利编译,并且简单的sample程序也可以运行(../dist/configure –enable-migw && make && make ex_access)。
对于你碰到的问题,如果db-4.7.25是很久以前编译的,建议重新编译一下db-4.7.25看看这次是否有问题。 如果有问题,说明系统可能不完整了。
如果没问题,请提供进一步的信息。比如:mingw的版本,gcc版本, 命令行工具所属系统(msys, cygwin, SFU 或其他), 环境变量的列表, config.log, 具体的编译出错信息等等。
@winterzhang
感謝你快速的回覆!
剛剛下了db-4.7.25.zip重新編譯, 是可以正常編譯成功的!
請問一下怎麼提供config.log給你? 謝謝!
我可以提供4.7.25與4.8.24的config.log還有4.8.24出錯的error msg給你.
@林林
我们不鼓励私下交流。通过blog或者论坛的形式来回答你的问题,可以让更多遇到相似问题的人受益。当然,如果你要投递BDB的文章,我们会帮助你审阅的。你写完后,可以把文章先发给我: chao.huang.
@chaohuang
为什么发email就不算私下交流呢?问题是私下交流非我的本意。我是将我修改后的代码发给原作者,总是要给他讲讲我的思路,如何调试我的代码,这样效率才会高吧。我担心的是我冒失的发email给他会被他当作垃圾邮件处理。还有,可能一开始他对我修改后的代码不知道如何入手,说不定很快就放弃了。通过qq交流两句就很快了。
@林林
我是David的老板。你有问题,创意,程序,文章等都可以先邮件发给我。我们应该能读懂你的代码。
@chaohuang
好的,没有问题,我明天整理一下就发过去。
您好, 关于 B树索引的压缩能否详细介绍下,能大概压缩多少百分比。
为了支持多种排序,我现在库有很多的二级库,造成空间的浪费,大概1000条记录要占用4MB(每条记录200字节)。
@林林
David的邮件地址:david.zhao at oracle dot com
我的是:chao.huang at oracle dot com
@wendy
Hi Wendy, Good question。我想十一长假后,再请相关同事给你解答。祝你长假快乐。
Thanks, Happy Holidays@chaohuang
@林林 你好,感谢你对dbstl的浓厚兴趣和你的代码。我前段时间挺忙的,后来又遇到休假,直到今天(虽然也还在休假)才看到你的诸多回复。
对于CDbArchive的设计,我之前也考虑过。这是我最初从mfc当中学到的技巧。不过后来我认识到,这样做的问题是:侵入性太大了。有很多类型是你只能只读地使用而不可以修改的,比如第三方的类库。你无法为它们再实现一个类似Java的Serializable接口,或者像mfc那有样在类声明当中放入一个宏定义。还有诸如char*, wchar_t*等类型,是无法使用继承/多态等特性的。
dbstl必须使用一个统一而且通用的方式来支持所有类型的这种用户可定制的marshal/unmarshal,所以最终我发现,使用一个模板DbstlElemTraits是符合所有需求的方法,而且实现起来和用起来都不麻烦。