예제 #1
0
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();
	}
예제 #2
0
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;
		}
	}
}