当前位置: 首页 > 工具软件 > FastDB > 使用案例 >

fastDB核心心得

欧君之
2023-12-01

学习背景:最近遇到了fastDB瓶颈的问题,经过仔细的研究fastDB的锁机制和内存机制,暂时记录如下。

fastdb的锁:fastdb是内存数据库,锁针对的是整个库的锁,所以在频繁写操作时会拖低系统的效率,这也是无奈之举。下面的分析是基于beginTransaction(事务分析的)

           在使用的时候打开数据库的权限中有几种方式:1。dbConcurrentUpdate //同时更新方式 2.dbConcurrentRead同时读方式。3dbAllAccess普通方式 4.dbReadOnly只读方式。

    在使用锁的时候会将传入的锁类型和打开数据库的权限结合确定锁的范围。

                   当dbConcurrentUpdate方式打开数据库时比较特殊:

                              当使用独占锁时:线程的ctx->isMutator = true (写标示)和ctx->mutatorCSLocked = true(临界区锁)

                               当使用共享锁时:ctx->mutatorCSLocked = true(临界区写锁)
                               当使用提交锁时:同下面使用提交锁的情况。

                    当以其他方式打开数据库(包括1和2结合在一起,或者3单独)(accessType!=dbConcurrentUpdate )

                                当使用独占锁和提交锁时:

                                         1.首先如果线程有写操作(ctx->writeAccess = true )则监控拥有进程必须是当前线程的进程

                                                  (monitor->ownerPid必须等于ctx->currPid) 否则出错。

                                        2.线程没有写操作有读操作时(ctx->readAccess = true ),数据库中不能存在写线程,这时数据库

                                                      读线程的数目为1则为当前读线程,只要将读计数设置为0,写线程置为1,数据库系统读线程数目不为1则

                                                      不能存在待更新线程,将数据库待写线程数加1,并设置waitForUpgrade为true.

                                                        monitor->ownerPid = ctx->currPid;ctx->writeAccess = true;

                                          3.线程没有读操作和写操作,如果数据库系统没有读写线程则将数据库写线程设置为1

                                                          monitor->ownerPid = ctx->currPid;ctx->writeAccess = true;

                                     当使用共享锁是:                                                                 
                                                  
                                              1.当前线程有读操作和写操作,则不执行。返回true

                                                 2. 线程无读操作和写操作,看数据库是否有写线程和待写线程
                                                              如果没有则数据库读线程加1,如果数据库有代写线程,写待读线程加1,等待写线程为0,同时处理僵死的写线程
                                                            ctx->readAccess = true;
总结如下:

独占锁:dbConcurrentUpdate的打开数据库方式:线程句柄上设置写标示并且进去数据库写临界区

                其它方式打开数据库,线程存在些操作则当前进程必须为监控进程,否则是错误的情况。线程存在读操作时数据库中不能有待写或者待更新线程

                                如果数据库读线程数目为1则为当前线程将计算为写线程并且待更新状态为true.若存在多个读线程和前面一样只不过这次读线程要计算为

                            写线程并且最后将monitor->ownerPid = ctx->currPid,线程写操作设置为true.(这里允许有多个读线程,但不能有写线程或者独占方式打开的读线程)

共享锁:    dbConcurrentUpdate的打开数据库方式,进入数据库写临界区。

             其它方式打开数据库,线程存在读或者写操作,直接返回true  线程不存在读写操作 时,看数据库系统是否有写线程,如果没有直接线程读操作计数加1,如果有

                                              

            

    FASTDB的内存:

FASTDB中有3中类型的内存:

1.在database构造函数中的bitmapPageAvailableSpace 直接new了一块大内存new int[dbBitmapId + dbBitmapPages]
 这块内存供自己后续做内存管理的工作,依赖于dbDatabaseOffsetBits的位数-dbBitmapSegmentBits(目前为19),其中

每一个int中存放的是每个bitmappage中能够使用的空间字节数。


2. open函数映射的文件内存,映射的起始地址为数据库的基地址//大小为文件低位字节大小

3.支持replicationSupport的nPages(数据库系统支持多少个4K)*sizeof(int);//应该是存放每个分页改变数据的大小
         npages=1 << (dbDatabaseOffsetBits - dbModMapBlockBits(12)) //32位(1M)//


fastdb位图:每个位代表16个字节,一次最少分配16字节
           每个字节代表(3+4)次幂个字节
           每32个字节代表一个4096的页
           每个page代表了一个segment(bitmappage)           
    所以一个bitmappage是12(一页字节)+3(每个字节)+4(一次分配16个字节)次幂个常用字节
  每页位图表示一个bitmappage,有多少数据库的分页就需要多少系统页(4KB)来表示。
  每个index指向一个位图的page,
  每个bitavliablebit存放每个数据库页的可用大小

当申请的空间+当前位置大于文件大小时要扩展文件大小的两倍,或者直接扩展到文件最大大小(0为无限大)

bitmap位图的原则是:每一位对应着16个字节,每一个字节对应8*16个字节,每32个字节对应一个传统页(4k),每个page对应着一个bitmappages(fastdb数据库段),

所以在使用了的内存上置1,分配内存是先从bitavliablebit中查看那个段有足够的空间,再从bitmap中寻找连续的为0的空位来分配,最后映射到对应的数据库段上。


                                                                                                 由于时间问题,粗略描述如下,有机会再进行详细补充.............

 类似资料: