内存映射文件原理_开源内存数据库

内存映射文件原理_开源内存数据库前言在前文LMDB简介的基础上,本文介绍LMDB数据库的基本用法,包括环境environment创建、数据存储put、数据读取get等;源码ULONGcvtest_Test4_Lmdb(){INTiRet;MDB_txn*pstTxn=NULL;MDB_dbistDbi;UINTuiKey=1;…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE稳定放心使用

前言

         在前文LMDB简介的基础上,本文介绍LMDB数据库的基本用法,包括环境environment创建、数据存储put、数据读取get等;

源码

ULONG cvtest_Test4_Lmdb()
{   
    INT iRet;
    MDB_txn *pstTxn = NULL;
    MDB_dbi stDbi;
    UINT uiKey = 1;
    UINT uiData = 100;
    
    iRet = mdb_env_create(&g_pstMdbEnv);
    if (0 != iRet)
    {
        return ERROR_FAILED;
    }
    mdb_env_set_maxreaders(g_pstMdbEnv, 1);
    mdb_env_set_mapsize(g_pstMdbEnv, 4096 * 4096);
    
    if (ERROR_SUCCESS != Lib_CreateDir(CVTEST_LMDB_PATH))
    {
        mdb_env_close(g_pstMdbEnv);
        return ERROR_FAILED;
    }
    iRet = mdb_env_open(g_pstMdbEnv, CVTEST_LMDB_PATH, MDB_WRITEMAP, 0);
    E(iRet, "Env open failed...");
    
    iRet += mdb_txn_begin(g_pstMdbEnv, NULL, 0, &pstTxn);
    E(iRet, "Txm begin open failed...");
    
    iRet += mdb_dbi_open(pstTxn, NULL, MDB_CREATE, &stDbi);
    E(iRet, "dbi_open failed...");
    
    MDB_val stKey;
    MDB_val stData;
    stKey.mv_size = sizeof(UINT);
    stKey.mv_data = (VOID *)&uiKey;

    /* mdb_put  存数据 */
    stData.mv_size = sizeof(UINT);
    stData.mv_data = (VOID *)&uiData;
    iRet = mdb_put(pstTxn, stDbi, &stKey, &stData, 0);
    if (iRet != MDB_SUCCESS)
    {
        printf("mdb_put failed : %s\n", mdb_strerror(iRet));
        mdb_env_close(g_pstMdbEnv);
        return ERROR_FAILED;
    }
    mdb_txn_commit(pstTxn);

    /* 重新begin一个事务---进行读 */
    MDB_txn *pstReadTxn = NULL;
    MDB_dbi stDbiRead;
    MDB_val stReadValue;    
    CHAR szBuf[BUF_LEN_100] = {0, };
    
    stReadValue.mv_size = BUF_LEN_100;
    stReadValue.mv_data = (VOID *)szBuf;
    mdb_txn_begin(g_pstMdbEnv, NULL, MDB_RDONLY, &pstReadTxn);
    iRet = mdb_dbi_open(pstReadTxn, NULL, 0, &stDbiRead);

    iRet += mdb_get(pstReadTxn, stDbiRead, &stKey, &stReadValue);
    if (iRet != MDB_SUCCESS)
    {
        printf("mdb_get failed : %s\n", mdb_strerror(iRet));
        return ERROR_FAILED;
    }
    printf("stReadValue.data is %d \n", *(UINT *)stReadValue.mv_data);
    return ERROR_SUCCESS;
}

源码解读

  1. 按照LMDB官方介绍文档,先通过mdb_env_create创建env,后续mdb_env_set_maxreaders、mdb_env_set_mapsize设置环境相关参数;
  2. Lib_CreateDir用于创建数据库的目录,官方文档有提及:mdb_env_open参数2并不会为用户创建相关目录,因而需要提前创建;
  3. mdb_env_open、mdb_txn_begin、mdb_dbi_open分别用于打开environment、打开一个事务、打开一个数据库instance。其中mdb_dbi_open通过不同的数据库名(param 2)支持多实例
  4. mdb_put用于存入相关数据:key/value对,key/value都是MDB_val结构;
  5. 后续mdb_get用户获取数据,key与put时的key相同,get成功后,我们通过强制类型转换取得数据库内的值并打印;
  6. E是笔者封装的一个宏定义,用于检查API的返回结果,如下:
#define E(Rest, expr) LMDB_CHECK((Rest) == MDB_SUCCESS, #expr)
#define LMDB_CHECK(test, msg) ((test) ? (void)0 : ((void)fprintf(stderr, \
         "%s:%d: %s: %s\n", __FILE__, __LINE__, msg, mdb_strerror(test)), abort()))

测试结果

         最后,我们将程序编译/得到,得到如下结果。

内存映射文件原理_开源内存数据库

 

         在相关目录产生数据文件和锁文件。

zglinux cvtest # ls -lrth /home/zhaogang/code_my/lmdb/
total 32K
---------- 1 root root 192 5月  27 21:29 lock.mdb
---------- 1 root root 16M 5月  27 21:29 data.mdb
zglinux cvtest #

结果表明:测试正确。

扩展说明

  1. LMDB通过DBI区分不同的数据库实例,支持在一个数据文件中存储多个数据库实例;
  2. LMDB是一个轻量级的开源数据库library,常用在硬件受限的嵌入式环境,不支持SQL语句
  3. LMDB通过mmap将文件映射到进程的虚拟地址空间,可加速数据库的访问;
  4. LMDB采用B+树算法存储数据,通过游标cursor可方便的访问不同位置的数据;
  5. LMDB的数据存/取都采用c语言中通用的void类型,其类型解析由程序员自行处理,提供更大的灵活性

总结

         LMDB全部源码12K行,想要进一步了解其实现的读者可以参阅其源码。源码中也提供mtest、mtest2~mtest6等多个测试案例供参阅。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/187959.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • es6数组方法图解

    es6数组方法图解最近接触了一些web前端开发人员,发现还是很多人不适用es6提供的语义化api。下面分享下看到的图解es6数组方法。很形象的es6数组方法解释:

  • 路由追踪:traceroute/tcptraceroute

    路由追踪:traceroute/tcptraceroute一.工作原理traceroute:IP路由过程中对数据包TTL(TimetoLive,存活时间)进行处理。当路由器收到一个IP包时,会修改IP包的TTL(及由此造成的头部检验和checksum变化)。每收到一个包,检查这个的TTL是否是0。如果是,表明这个包还没有到达目的地,而且剩余时间不多了,肯定是到不了目的地了。这样路由器就简单地丢弃这个包,并给源主机发送ICMP通知,说这个包已经…

  • mpc hc设置_mpc是指什么

    mpc hc设置_mpc是指什么MPC-HC播放器设置启动 MPC-HC ,先设置语言:(最新版本会自动选择对应的系统语言)View-Language-Chinese=>界面变为中文进 视图-选项:播放器:建议勾选「保存设置至.ini文件中」格式:建议勾选全部视频类格式,其中 QuickTime 建议采用「DirectShow」滤镜(双击右侧,在下拉框中即可选择),播放性能会

  • spring boot框架介绍_Spring框架是什么

    spring boot框架介绍_Spring框架是什么前面的铺垫文章已经连着写了六篇了,主要是介绍了Spring和SpringMVC框架,小伙伴们在学习的过程中大概也发现了这两个框架需要我们手动配置的地方非常多,不过做JavaEE开发的小伙伴们肯定也听说过“约定大于配置”这样一句话,就是说系统,类库,框架应该假定合理的默认值,而非要求提供不必要的配置,可是使用Spring或者SpringMVC的话依然有许多这样的东西需要我们进行配置,这样不仅徒增工作量

  • WiFi(6)和5G的区别及比对[通俗易懂]

    WiFi(6)和5G的区别及比对[通俗易懂]5G是蜂窝数字移动通信技术,既可用于广域高速移动通信,又可用于室内无线上网,具有传输速率高、时延小、并发能力强等优点,但系统复杂、成本高。WiFi6是无线接入技术,主要用于室内无线终端上网,具有传输速率高、系统简单、成本低等优点,但不适用于高速移动通信。5G和WiFi6具有以下特点:(1)5G上行峰值传输速率达10Gbit/s,下行峰值传输速率达20Gbit/s。WIFI6在80MHz带宽下,单条空间流的峰值速率为600Mbit/s,在带宽为160MHz、8条空间流的情况下,峰值速率达9.

  • c++容器类_类的容器

    c++容器类_类的容器什么是容器首先,我们必须理解一下什么是容器,在C++中容器被定义为:在数据存储上,有一种对象类型,它可以持有其它对象或指向其它对像的指针,这种对象类型就叫做容器。很简单,容器就是保存其它对象的对象,当然这是一个朴素的理解,这种“对象”还包含了一系列处理“其它对象”的方法,因为这些方法在程序的设计上会经常被用到,所以容器也体现了一个好处,就是“容器类是一种对特定代码重用问题的良好的解决方案”

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号