`

MDB记录锁实现细节

 
阅读更多

内存数据库实现中涉及数据的同步一致性问题,可以实现高效的记录锁来尽量减少同步的开销。

下图是一个内存数据库数记录锁的实现分析:




 一个MDB服务端中会包含多个Table,每个Table会包含一个或多个Index键值,操作某张表中数据记录时需要对该表中某个键值加锁,就会锁定该条记录不再被其他线程同时操作。每个MDB服务库中会包含一个内存命名锁管理器(CNamedLockMemMgr),该MDB服务初始化时针对每个Table中的索引键值都创建一个内存命名锁(CNamedLockMem)并返回锁的在命名锁管理器中索引,后续锁操作时指定该索引即可。

命名锁管理器提供的锁操作接口为:

void lock(CLockInfo* pLockInfo, int64 llID, CLockSession& cLockSession )

void lock(CLockInfo* pLockInfo, CFSet<int64>& lstID, CLockSession& cLockSession )

int32 is_lock(CLockInfo* pLockInfo, int64 llID, CLockSession& cLockSession)

void unlock(CLockInfo* pLockInfo, CLockSession& cLockSession )

 

对某个表的键值key加锁过程如下:

1、通过初始化时得到的该表的Index列键值锁信息CLockInfo来找到其位于命名锁管理器中创建的内存命名锁(CNamedLockMem)对象;

2、将键值Key插入找到的CNamedLockMem对象的已锁定键值Set中,调用内部的CNamedLock对象对键值Key加锁;

3、CNamedLock根据建锁信息中指定的m_nLockModule数,创建了相应的多记录锁(CMultiLock)对象,对某个键值Key根据m_nLockModule取模,即可以得到要操作的多记录锁对象。

4、得到多记录锁对象(CMultiLock)进行lock操作,CMultiLock对象内部维护了通过该锁Lock的所有记录的信息,包含锁定的键值、键值当前锁定的状态、当前锁定该键值的线程和事务号、等待该锁的线程数、该锁的加锁时间。

void lock(const T& data, CLockSession& cLockSession )

{

               pthread_mutex_lock( &m_lock); //操作内部锁定记录信息时需互斥加锁

               int nPos = add_data( data);  //如果不存键值Key信息,需要扩展增加锁记录数组

 

               if(m_pLockSession[nPos].m_llThreadID == cLockSession.m_llThreadID && 

                  m_pLockSession[nPos].m_llSessionID == cLockSession.m_llSessionID &&

                  m_pLockStatus[nPos] 

                )

               {//同一个线程和事务已经锁定该记录的处理

                            pthread_mutex_unlock( &m_lock);

 

                           if(CMultiLockAttr::get_recurLockFlag())

                           {

                                          return;

                           }

                           else

                           {

                                         THROW_MFEXCEPTION(MF_ERROR_LOCK_FAILED, "recursive lock failed ");

                             }

                  }

 

                 m_pWanted[nPos]++;  //等待该锁的数量+1

                 timespec   ts;

                 int     iTime = 0;

 

                while( m_pLockStatus[nPos])

                {//该记录已被其他线程或事务锁定

                           if(CMultiLockAttr::get_timedLockFlag())

                           {//超时锁

                                       if(iTime ==0 )

                                      {//设定锁超时时间

                                             clock_gettime(CLOCK_REALTIME, &ts);

                                             ts.tv_sec += CMultiLockAttr::get_lockTime();

                                             iTime ++;

                                      }

 

                                      if(ETIMEDOUT == pthread_cond_timedwait( &m_cond, &m_lock, &ts))

                                      {

                                                 m_pWanted[nPos]--;

                                                 pthread_mutex_unlock( &m_lock);

 

                                                THROW_MFEXCEPTION(MF_ERROR_LOCK_TIMEOUT, "timed lock timedout");

 

                                     }

                         }

                         else

                        {//交出执行权等待解锁事件

                                 pthread_cond_wait( &m_cond, &m_lock);

                         }

                }

               //获取到锁

               m_pLockStatus[nPos] = 1;

               m_pLockSession[nPos].m_llThreadID = cLockSession.m_llThreadID;

               m_pLockSession[nPos].m_llSessionID = cLockSession.m_llSessionID;

               m_pWanted[nPos]--;

               pthread_mutex_unlock( &m_lock);

}

 

void unlock(const T& data, CLockSession& cLockSession )

{

                pthread_mutex_lock( &m_lock);

               int  nPos = find_data( data);

               if( nPos != -1 && 

               ( m_pLockSession[nPos].m_llThreadID == cLockSession.m_llThreadID ||                  cLockSession.m_llThreadID == 0 ) && 

               ( m_pLockSession[nPos].m_llSessionID == cLockSession.m_llSessionID || cLockSession.m_llSessionID == 0 ) )

             {

                       m_pLockStatus[nPos] = 0;

                       m_pLockSession[nPos].m_llThreadID = 0;

                       m_pLockSession[nPos].m_llSessionID = 0;

                       if( m_pWanted[nPos])

                      {//有其他人在等待,广播解锁事件

                                pthread_cond_broadcast( &m_cond);

                      }

             }

 

             pthread_mutex_unlock( &m_lock);

}

 

  • 大小: 81.4 KB
分享到:
评论

相关推荐

    MDB的学习资料

    2. **创建线程互斥**:通过锁文件实现,确保MDB在多线程环境下的唯一性和安全性。 3. **读取配置文件**:将MDB参数读入私有内存,为后续操作提供必要的信息。 4. **控制文件与表空间创建**:构建控制表空间文件,...

    mdb内存数据库源代码和注释

    通过深入分析mdb的源代码,我们可以更详细地了解这些机制的实现细节。例如,mdb如何通过位图来记录数据页的占用情况,如何优化B+树的插入和删除操作,以及如何实现不同类型的锁策略等。同时,结合作者的论文,我们...

    智能门锁系统V8门锁接口,适用于美萍酒店管理最新版本

    lockdata.mdb 这个文件看起来是一个Microsoft Access 数据库,很可能存储了门锁的操作记录和相关数据,如开锁历史、用户信息、房间状态等。这种数据库结构使得数据管理更加高效,方便进行数据分析和报告。 说明.txt...

    易语言网吧键盘锁源码-易语言

    例如,`pb.ec`可能是程序的错误日志文件,`rj.es`可能是运行时库文件,`db.ldb`和`db.mdb`可能分别代表数据库的日志文件和主数据文件,用于存储键盘锁的相关配置或历史记录。 总的来说,"易语言网吧键盘锁源码"是一...

    ASP连接数据库五种方法

    1. **游标类型**:在使用Recordset对象时,可以设置不同的游标类型来优化性能或实现特定功能。 - `adOpenForwardOnly`: 只能向前遍历的游标,效率最高。 - `adOpenKeyset`: 支持向前和向后遍历,但不支持删除记录...

    VB连接ACCESS数据库

    在软件开发过程中,经常需要通过编程语言来实现对数据库的操作。Visual Basic(简称VB)作为一款经典的编程语言,在处理Windows应用程序时有着广泛的应用场景。其中,连接并操作Access数据库是VB应用中的一个重要...

    ASP 电子表格数据导入access源码,超好用。

    分析这个文件的内容可以帮助我们更好地理解具体实现的细节。 总结来说,这个ASP源码提供了将Excel(xls和xlsx格式)数据导入Access数据库的功能,通过创建Excel对象读取数据,然后使用ADO连接Access数据库并执行...

    SCBCD_NOTES_JIAFAN

    - **乐观锁**:通过版本号或时间戳等手段实现并发控制,防止数据冲突。 ### EJB Object and EJB Context #### 8.1 一般规则 - **EJB Object**:提供远程接口的EJB组件,允许其他组件或客户端远程调用。 - **EJB ...

    超级有影响力霸气的Java面试题大全文档

    通常性能上较ArrayList差,而LinkedList使用双向链表实现存储,按序号索引数据需要进行前向或后向遍历,但是插入数据时只需要记录本项的前后项即可,所以插入速度较快。 11、EJB是基于哪些技术实现的?并说出...

Global site tag (gtag.js) - Google Analytics