void MasterDBRMNode::msgProcessor() { struct ThreadParams *p; ByteStream msg; vector<ByteStream *> responses; vector<ByteStream *>::iterator it; int err; uint8_t cmd; StopWatch timer; #ifdef BRM_VERBOSE cerr << "DBRM Controller: msgProcessor()" << endl; #endif mutex2.lock(); p = params; mutex2.unlock(); #ifndef __FreeBSD__ mutex.unlock(); #endif while (!die) { try { msg = p->sock->read(&MSG_TIMEOUT); } catch (...) { THREAD_EXIT throw; } if (die) // || msg.length() == 0) break; else if (msg.length() == 0) continue; /* Check for an command for the master */ msg.peek(cmd); #ifdef BRM_VERBOSE cerr << "DBRM Controller: recv'd message " << (int)cmd << " length " << msg.length() << endl; #endif switch (cmd) { case HALT: doHalt(p->sock); continue; case RESUME: doResume(p->sock); continue; case RELOAD: try { doReload(p->sock); } catch (exception &e) { cerr << e.what() << endl; } continue; case SETREADONLY: doSetReadOnly(p->sock, true); continue; case SETREADWRITE: doSetReadOnly(p->sock, false); continue; case GETREADONLY: doGetReadOnly(p->sock); continue; } /* Process SessionManager calls */ switch (cmd) { case VER_ID: doVerID(msg, p); continue; case SYSCAT_VER_ID: doSysCatVerID(msg, p); continue; case NEW_TXN_ID: doNewTxnID(msg, p); continue; case COMMITTED: doCommitted(msg, p); continue; case ROLLED_BACK: doRolledBack(msg, p); continue; case GET_TXN_ID: doGetTxnID(msg, p); continue; case SID_TID_MAP: doSIDTIDMap(msg, p); continue; case GET_UNIQUE_UINT32: doGetUniqueUint32(msg, p); continue; case GET_UNIQUE_UINT64: doGetUniqueUint64(msg, p); continue; case GET_SYSTEM_STATE: doGetSystemState(msg, p); continue; case SET_SYSTEM_STATE: doSetSystemState(msg, p); continue; case CLEAR_SYSTEM_STATE: doClearSystemState(msg, p); continue; case SM_RESET: doSessionManagerReset(msg, p); continue; } /* Process TableLock calls */ switch (cmd) { case GET_TABLE_LOCK: doGetTableLock(msg, p); continue; case RELEASE_TABLE_LOCK: doReleaseTableLock(msg, p); continue; case CHANGE_TABLE_LOCK_STATE: doChangeTableLockState(msg, p); continue; case CHANGE_TABLE_LOCK_OWNER: doChangeTableLockOwner(msg, p); continue; case GET_ALL_TABLE_LOCKS: doGetAllTableLocks(msg, p); continue; case RELEASE_ALL_TABLE_LOCKS: doReleaseAllTableLocks(msg, p); continue; case GET_TABLE_LOCK_INFO: doGetTableLockInfo(msg, p); continue; case OWNER_CHECK: doOwnerCheck(msg, p); continue; } /* Process OIDManager calls */ switch (cmd) { case ALLOC_OIDS: doAllocOIDs(msg, p); continue; case RETURN_OIDS: doReturnOIDs(msg, p); continue; case OIDM_SIZE: doOidmSize(msg, p); continue; case ALLOC_VBOID: doAllocVBOID(msg, p); continue; case GETDBROOTOFVBOID: doGetDBRootOfVBOID(msg, p); continue; case GETVBOIDTODBROOTMAP: doGetVBOIDToDBRootMap(msg, p); continue; } /* Process Autoincrement calls */ switch (cmd) { case START_AI_SEQUENCE: doStartAISequence(msg, p); continue; case GET_AI_RANGE: doGetAIRange(msg, p); continue; case RESET_AI_SEQUENCE: doResetAISequence(msg, p); continue; case GET_AI_LOCK: doGetAILock(msg, p); continue; case RELEASE_AI_LOCK: doReleaseAILock(msg, p); continue; case DELETE_AI_SEQUENCE: doDeleteAISequence(msg, p); continue; } retrycmd: uint32_t haltloops = 0; while (halting && ++haltloops < static_cast<uint32_t>(FIVE_MIN_TIMEOUT.tv_sec)) sleep(1); slaveLock.lock(); if (haltloops == FIVE_MIN_TIMEOUT.tv_sec) { ostringstream os; os << "A node is unresponsive for cmd = " << (uint32_t)cmd << ", no reconfigure in at least " << FIVE_MIN_TIMEOUT.tv_sec << " seconds. Setting read-only mode."; log(os.str()); readOnly = true; halting = false; } if (readOnly) { SEND_ALARM slaveLock.unlock(); sendError(p->sock, ERR_READONLY); goto out; } /* TODO: Separate these out-of-band items into separate functions */ /* Need to get the dbroot, convert to vbOID */ if (cmd == BEGIN_VB_COPY) { try { boost::mutex::scoped_lock lk(oidsMutex); uint8_t *buf = msg.buf(); // dbroot is currently after the cmd and transid uint16_t *dbRoot = (uint16_t *) &buf[1+4]; // If that dbroot has no vboid, create one int16_t err; err = oids.getVBOIDOfDBRoot(*dbRoot); //cout << "dbRoot " << *dbRoot << " -> vbOID " << err << endl; if (err < 0) { err = oids.allocVBOID(*dbRoot); // cout << " - allocated oid " << err << endl; } *dbRoot = err; } catch (exception& ex) { ostringstream os; os << "DBRM Controller: Begin VBCopy failure. " << ex.what(); log(os.str()); sendError(p->sock, -1); goto out; } } /* Check for deadlock on beginVBCopy */ /* if (cmd == BEGIN_VB_COPY) { ByteStream params(msg); VER_t txn; uint8_t tmp8; uint32_t tmp32; LBIDRange_v ranges; LBIDRange_v::iterator it; LBID_t end; params >> tmp8; //throw away the cmd params >> tmp32; txn = tmp32; deserializeVector(params, ranges); for (it = ranges.begin(); it != ranges.end(); it++) { end = (*it).start + (*it).size - 1; err = rg->reserveRange((*it).start, end, txn, slaveLock); if (err != ERR_OK) { pthread_mutex_unlock(&slaveLock); sendError(p->sock, err); goto out; } } } */ /* Release all blocks of lbids on vbRollback or vbCommit */ if (cmd == VB_ROLLBACK1 || cmd == VB_ROLLBACK2 || cmd == VB_COMMIT) { ByteStream params(msg); VER_t txn; uint8_t tmp8; uint32_t tmp32; params >> tmp8; params >> tmp32; txn = tmp32; rg->releaseResources(txn); } /* XXXPAT: If beginVBCopy, vbRollback, or vbCommit fail for some reason, the resource graph will be out of sync with the copylocks and/or vss. There are 2 reasons they might fail: 1) logical inconsistency between the resource graph and the copylocks & vss 2) "out of band" failures, like a network problem */ /* Need to atomically do the safety check and the clear. */ if (cmd == BRM_CLEAR) { uint32_t txnCount = sm.getTxnCount(); // do nothing if there's an active transaction if (txnCount != 0) { ByteStream *reply = new ByteStream(); *reply << (uint8_t) ERR_FAILURE; responses.push_back(reply); goto no_confirm; } } try { distribute(&msg); } catch (...) { if (!halting) { SEND_ALARM undo(); readOnly = true; slaveLock.unlock(); ostringstream ostr; ostr << "DBRM Controller: Caught network error. " "Sending command " << (uint32_t)cmd << ", length " << msg.length() << ". Setting read-only mode."; log(ostr.str()); sendError(p->sock, ERR_NETWORK); goto out; } } #ifdef BRM_VERBOSE cerr << "DBRM Controller: distributed msg" << endl; #endif bool readErrFlag; // ignore this flag in this case err = gatherResponses(cmd, msg.length(), &responses, readErrFlag); #ifdef BRM_VERBOSE cerr << "DBRM Controller: got responses" << endl; #endif CHECK_ERROR1(err) err = compareResponses(cmd, msg.length(), responses); #ifdef BRM_VERBOSE cerr << "DBRM Controller: compared responses" << endl; #endif #ifdef BRM_DEBUG if ((cmd == BEGIN_VB_COPY || cmd == VB_ROLLBACK1 || cmd == VB_ROLLBACK2 || cmd == VB_COMMIT) && err == -1) cerr << "DBRM Controller: inconsistency detected between the resource graph and the VSS or CopyLocks logic." << endl; #endif // these command will have error message carried in the response if (!responses.empty() && (cmd == DELETE_PARTITION || cmd == MARK_PARTITION_FOR_DELETION || cmd == RESTORE_PARTITION) && err) { if (err != ERR_PARTITION_DISABLED && err != ERR_PARTITION_ENABLED && err != ERR_INVALID_OP_LAST_PARTITION && err != ERR_NOT_EXIST_PARTITION && err != ERR_NO_PARTITION_PERFORMED) undo(); //goto no_confirm; } else { CHECK_ERROR1(err) } // these cmds don't need the 2-phase commit if (cmd == FLUSH_INODE_CACHES || cmd == BRM_CLEAR || cmd == TAKE_SNAPSHOT) goto no_confirm; #ifdef BRM_VERBOSE cerr << "DBRM Controller: sending confirmation" << endl; #endif try { confirm(); } catch (...) { if (!halting) { SEND_ALARM ostringstream ostr; ostr << "DBRM Controller: Caught network error. " "Confirming command " << (uint32_t)cmd << ", length " << msg.length() << ". Setting read-only mode."; log(ostr.str()); readOnly = true; } } no_confirm: slaveLock.unlock(); try { p->sock->write(*(responses.front())); } catch (...) { p->sock->close(); log("DBRM Controller: Warning: could not send the reply to a command", logging::LOG_TYPE_WARNING); } out: for (it = responses.begin(); it != responses.end(); it++) delete *it; responses.clear(); }
void Decoder::decodeVariation(ByteStream& data) { unsigned pieceNum = 0; // satisfies the compiler Move move; while (true) { Byte b; while ((b = m_strm.get()) > token::End_Marker) { if (move) m_position.doMove(move, pieceNum); pieceNum = decodeMove(b, move); MoveNode* node = new MoveNode(move); m_currentNode->setNext(node); m_currentNode = node; } switch (b) { case token::End_Marker: { MoveNode* node = new MoveNode; m_currentNode->setNext(node); switch (m_strm.get()) { case token::Comment: node->setCommentFlag(data.get()); break; case token::End_Marker: break; default: return; //IO_RAISE(Game, Corrupted, "unexpected token"); } } return; case token::Start_Marker: { MoveNode* current = m_currentNode; m_position.push(); m_position.board().undoMove(move); current->addVariation(m_currentNode = new MoveNode); decodeVariation(data); m_currentNode = current; m_position.pop(); } break; case token::Nag: static_assert(Annotation::Max_Nags >= 7, "Scidb needs at least seven entries"); { nag::ID nag = nag::ID(m_strm.get()); if (nag == 0) move.setLegalMove(false); else m_currentNode->addAnnotation(nag); } break; case token::Mark: if (data.peek() & 0x80) { MoveInfo info; info.decode(data); m_currentNode->addMoveInfo(info); } else { Mark mark; mark.decode(data); m_currentNode->addMark(mark); } break; case token::Comment: m_currentNode->setCommentFlag(data.get()); break; } } }