void ResourceNode::wakeAndDetach() { TransactionNode *txn; set<RGNode *>::iterator sit; set<RGNode *>::iterator dummy_sit; for (sit = in.begin(); sit != in.end(); ) { txn = dynamic_cast<TransactionNode *>(*sit); txn->wake(); dummy_sit = ++sit; removeInEdge(txn); sit = dummy_sit; } in.clear(); }
LBIDResourceGraph::~LBIDResourceGraph() { std::map<VER_t, TransactionNode *>::iterator tnit; RNodes_t::iterator rit; TransactionNode *txnNode; for (tnit = txns.begin(); tnit != txns.end(); ) { txnNode = (*tnit).second; if (txnNode->sleeping()) { txnNode->die(); txnNode->wake(); ++tnit; } else { txns.erase(tnit++); delete txnNode; } } for (rit = resources.begin(); rit != resources.end(); ) { delete *rit; resources.erase(rit++); } }
void LBIDResourceGraph::releaseResources(VER_t txn) { /* get transaction node get all inbound nodes detach them and wake all txns on the in-edges delete the resource nodes get all outbound nodes (this can happen if a rollback comes in while blocked) detach them if txnNode isn't sleeping, delete the transaction node else mark it dead and wake it */ TransactionNode *txnNode; ResourceNode *rNode; map<VER_t, TransactionNode *>::iterator it; set<RGNode *>::iterator sit; set<RGNode *>::iterator dummy_sit; it = txns.find(txn); if (it == txns.end()) return; txnNode = (*it).second; for (sit = txnNode->in.begin(); sit != txnNode->in.end(); ) { rNode = dynamic_cast<ResourceNode *>(*sit); dummy_sit = ++sit; rNode->wakeAndDetach(); txnNode->removeInEdge(rNode); resources.erase(rNode); delete rNode; sit = dummy_sit; } for (sit = txnNode->out.begin(); sit != txnNode->out.end(); ) { rNode = dynamic_cast<ResourceNode *>(*sit); dummy_sit = ++sit; txnNode->removeOutEdge(rNode); sit = dummy_sit; } if (txnNode->sleeping()) { txnNode->die(); txnNode->wake(); } else { txns.erase(txn); delete txnNode; } }
/* 0 = OK 1 = transaction node was not found on wake -1 = deadlock detected, transaction node destroyed and resources released mutex should be slavelock */ int LBIDResourceGraph::reserveRange(LBID_t start, LBID_t end, VER_t txn, boost::mutex &mutex) { TransactionNode *txnNode; map<VER_t, TransactionNode *>::iterator it; /* look for existing transaction node T - make one if necessary connectResources(); checkDeadlock(); while (txnNode.out.size() > 0) block on T's condvar connectResources(); checkDeadlock(); } */ it = txns.find(txn); if (it == txns.end()) { txnNode = new TransactionNode(txn); txns[txn] = txnNode; } else txnNode = (*it).second; connectResources(start, end, txnNode); // "If txnNode is waiting on at least one LBID range..." while (txnNode->out.size() > 0) { // make sure there's no deadlock before blocking if (checkDeadlock(*txnNode)) { // releaseResources(txn); return ERR_DEADLOCK; } #ifdef BRM_VERBOSE cerr << " RG: sleeping transaction " << txn << endl; set<RGNode *>::iterator sit; cerr << " waiting on: " << endl; for (sit = txnNode->out.begin(); sit != txnNode->out.end(); sit++) { ResourceNode *rn = dynamic_cast<ResourceNode *>(*sit); cerr << hex << rn << dec << " " << rn->lbid() << endl; } #endif txnNode->sleep(mutex); #ifdef BRM_VERBOSE cerr << " RG: txn " << txn << " is awake" << endl; #endif if (txnNode->dead()) { txns.erase(txn); delete txnNode; return ERR_KILLED; } // attempt to grab remaining resources connectResources(start, end, txnNode); } // txn has all requested LBID ranges return ERR_OK; }