資料庫讀寫鎖的實現(C++)
一、基本概念
在資料庫中,對某資料的兩個基本操作為寫和讀,分佈有兩種鎖控制:排它鎖(X鎖)、共享鎖(S鎖)。
排它鎖(x鎖):若事務T對資料D加X鎖,則其它任何事務都不能再對D加任何型別的鎖,直至T釋放D上的X鎖;
一般要求在修改資料前要向該資料加排它鎖,所以排它鎖又稱為寫鎖。
共享鎖(s鎖):若事務T對資料D加S鎖,則其它事務只能對D加S鎖,而不能加X鎖,直至T釋放D上的S鎖;
一般要求在讀取資料前要向該資料加共享鎖, 所以共享鎖又稱讀鎖。
程式所收到的請求包括以下五種:Start、End、XLock、SLock、Unlock
Start:開啟相應的事件請求
End: 關閉相應的事件請求
XLock: 對資料物件D新增X鎖,進行寫操作(當事件以對資料A加入S鎖時,此時可升級為X鎖)
SLock: 對資料物件D新增S鎖,進行讀操作
Unlock: 對資料物件D進行解鎖(對資料D的X/S鎖解綁,並檢查等待佇列)
本程式並不進行死鎖檢測以及死鎖預防,對於等待佇列採取FIFO原則進行。
二、資料結構
讀寫鎖維護一個數據D的狀態表,標記當前資料D的實時狀態,鎖表的資訊隨著事務的執行動態更新,反映當前的鎖狀態。
其資料結構如下圖所示:
其中:mObjectList:為map結構的物件樹,可方便快速查詢相應物件。
objectName:為物件資料D的名稱
curXLockTrans: 為當前寫操作的事件
waitingTransList: 為寫等待佇列
shareList: 為共享集(當curXLockTrans不為空時,變為共享等待佇列)
事件ID的資料結構如下:
其中:mTransId: 為map結構的事件樹,可以快速的查詢相應事件
tranId: 為事件名稱
curLockObjList: 為此事件目前所操作的物件列表
三、原始碼
本程式為所的鎖管理介面,所以封裝成類,方便程式呼叫。程式原始碼可以點選這裡下載。
資料結構如下:
邏輯結構實現如下:class LMer { private: struct object { string objectName; string curXLockTrans; queue<string> waitingTransList; set<string> shareList; }; struct transId { string tranId; set<object*> curLockObjList; }; map<string, object*> mObjectList; map<string, transId*> mTransId; public: LMer(){} string LMer::handleInput(vector<string>& vInput); void LMer::handleAction(string sAction, transId* trId, object* obj, string& result); void LMer::diviTransID(transId* trId, object* pObj, string& result); };
string LMer::handleInput(vector<string>& vInput)
{
string result = "";
//二引數輸入
if (vInput.size() == 2)
{ //程序存在,進入下一步
map<string, transId*>::iterator transIt = mTransId.find(vInput[1]);
if (transIt != mTransId.end())
{
//是否結束事件(結束事件佇列中所有事件)
if (vInput[0] == "End")
{
result += "\tTransaction "+ vInput[1] +" ended\n\t\t\t";
//解綁程序所有事物
set<object*>::iterator obj_index;
while(transIt->second->curLockObjList.size() != 0)
{
obj_index = transIt->second->curLockObjList.begin();
diviTransID(transIt->second, *obj_index, result);
}
//清空請求事件
mTransId.erase(transIt);
}
}
else if(vInput[0] == "Start")//為start,創立程序
{
transId* pTransId = new transId();
pTransId->tranId = vInput[1];
//將此程序加入程序樹中
mTransId[vInput[1]] = pTransId;
result += "Transaction " + vInput[1] +" started\n";
}
}
else //三引數輸入
{ //建立新操作物件
if(mObjectList.find(vInput[2]) == mObjectList.end())
{
object* pObjectIndex = new object();
pObjectIndex->objectName = vInput[2];
pObjectIndex->curXLockTrans = "";
mObjectList[vInput[2]] = pObjectIndex;
}
if (vInput[0] == "Unlock")
{
//解鎖trans->obj
diviTransID(mTransId[vInput[1]], mObjectList[vInput[2]], result);
}
else//進行常規處理(Xlock、Slock)
{
//進行處理
handleAction(vInput[0], mTransId[vInput[1]], mObjectList[vInput[2]], result);
}
}
return result;
}
void LMer::handleAction(string sAction, transId* trId, object* obj, string& result)
{
//檢查是否有佔用
if (sAction == "SLock")
{
if (obj->curXLockTrans == "")
{
obj->shareList.insert(trId->tranId);
trId->curLockObjList.insert(obj);
result += "S-Lock granted to "+ trId->tranId +"\n";
}
else//被佔用
{
obj->shareList.insert(trId->tranId);
result += "Waiting for lock (X-lock held by: "+ obj->curXLockTrans +")\n";
}
}
else if(sAction == "XLock")
{
//未有寫操作
if (obj->curXLockTrans == "")
{
int shareNum = obj->shareList.size();
if (shareNum > 1)
{
string sTemp = "";
for (set<string>::iterator it_index = obj->shareList.begin();
it_index != obj->shareList.end(); it_index++)
{
sTemp += " " + *it_index;
}
obj->waitingTransList.push(trId->tranId);
result += "Waiting for lock (S-lock held by:" + sTemp + "\n";
}
else if (shareNum == 1)
{
//update
if (*(obj->shareList.begin()) == trId->tranId)
{
obj->curXLockTrans = trId->tranId;
obj->shareList.clear();
result += "Upgrade to XLock granted\n";
}
else
{
obj->waitingTransList.push(trId->tranId);
result += "Waiting for lock (S-lock held by:" + *(obj->shareList.begin()) + ")\n";
}
}
else if (shareNum == 0)
{
obj->curXLockTrans = trId->tranId;
trId->curLockObjList.insert(obj);
result += "XLock granted\n";
}
}
else//當前存在寫操作
{
obj->waitingTransList.push(trId->tranId);
result += "Waiting for lock (X-lock held by: "+ obj->curXLockTrans +")\n";
}
}
}
void LMer::diviTransID(transId* trId, object* pObj, string& result)
{
if(pObj->curXLockTrans != "")
{
//對寫操作解綁
if (pObj->curXLockTrans == trId->tranId)
{
pObj->curXLockTrans = "";
trId->curLockObjList.erase(pObj);
result += "Lock released\n\t\t\t";
}
else
{
result += "I can not find the transaction.\n\t\t\t";
}
}//對共享讀集合解綁
else
{
set<string>::iterator shareIndex = pObj->shareList.find(trId->tranId);
if (shareIndex != pObj->shareList.end())
{
pObj->shareList.erase(shareIndex);
trId->curLockObjList.erase(pObj);
result += "Lock released\n\t\t\t";
}
else
{
result += "I can not find the transaction.\n\t\t\t";
}
}
//檢視寫等待佇列
if (pObj->waitingTransList.size() != 0)
{
pObj->curXLockTrans = pObj->waitingTransList.front();
pObj->waitingTransList.pop();
result += "X-Lock on "+ pObj->objectName +" granted to "+ pObj->curXLockTrans +"\n";
}//檢視共享佇列
else if (pObj->shareList.size() != 0)
{
string temp = "";
for(set<string>::iterator it_index = pObj->shareList.begin();
it_index != pObj->shareList.end(); it_index++)
{
temp += " " + *it_index;
}
result += "S-Lock on "+ pObj->objectName +" granted to "+ temp +"\n";
}
}
四、程式執行
程式資料輸入如下:
執行後得到結果如下: