simplify state table, getting rid of a bunch of states: we never leave

ALLCOND until it's time to kill the cref.  When one device connects
and leaves the cref is recycled, so when a new device joins and is
assigned the same game and a new cref is initialized the number of
players already registered must be set from the db entry; do that.
This commit is contained in:
Andy2 2010-09-16 18:59:56 -07:00
parent 76e7459a6d
commit 1490b2def9
8 changed files with 72 additions and 114 deletions

View file

@ -81,7 +81,7 @@ SocketsIterator::Next()
void
CookieRef::ReInit( const char* cookie, const char* connName, CookieID id,
int langCode, int nPlayers )
int langCode, int nPlayers, int nAlreadyHere )
{
m_cookie = cookie==NULL?"":cookie;
m_connName = connName==NULL?"":connName;
@ -90,7 +90,7 @@ CookieRef::ReInit( const char* cookie, const char* connName, CookieID id,
m_curState = XWS_INITED;
m_nextHostID = HOST_ID_SERVER;
m_nPlayersSought = nPlayers;
m_nPlayersHere = 0;
m_nPlayersHere = nAlreadyHere;
m_locking_thread = 0;
m_starttime = uptime();
m_gameFull = false;
@ -112,10 +112,10 @@ CookieRef::ReInit( const char* cookie, const char* connName, CookieID id,
CookieRef::CookieRef( const char* cookie, const char* connName, CookieID id,
int langCode, int nPlayers )
int langCode, int nPlayersT, int nAlreadyHere )
{
pthread_mutex_init( &m_mutex, NULL );
ReInit( cookie, connName, id, langCode, nPlayers );
ReInit( cookie, connName, id, langCode, nPlayersT, nAlreadyHere );
}
CookieRef::~CookieRef()
@ -269,18 +269,6 @@ CookieRef::SocketForHost( HostID dest )
return socket;
}
/* The idea here is: have we never seen the XW_ST_ALLCONNECTED state. This
needs to include any states reachable from XW_ST_ALLCONNECTED from which
recovery back to XW_ST_ALLCONNECTED is possible. This is used to decide
whether to admit a connection based on its cookie -- whether that coookie
should join an existing cref or get a new one? */
bool
CookieRef::NeverFullyConnected()
{
return m_curState != XWS_ALLCONND
&& m_curState != XWS_MISSING;
}
bool
CookieRef::GameOpen( const char* cookie )
{
@ -521,22 +509,6 @@ CookieRef::pushLastSocketGoneEvent()
m_eventQueue.push_back( evt );
}
void
CookieRef::checkHaveRoom( const CRefEvent* evt )
{
CRefEvent newEvt;
assert ( m_nPlayersSought > 0 );
if ( m_nPlayersSought < m_nPlayersHere + evt->u.con.nPlayersH ) {
newEvt.type = XWE_TOO_MANY;
newEvt.u.rmsock.socket = evt->u.con.socket;
} else {
newEvt = *evt;
newEvt.type = XWE_HAVE_ROOM;
}
m_eventQueue.push_back( newEvt );
}
void
CookieRef::handleEvents()
{
@ -558,10 +530,6 @@ CookieRef::handleEvents()
switch( takeAction ) {
case XWA_CHECK_HAVE_ROOM:
checkHaveRoom( &evt );
break;
case XWA_SEND_CONNRSP:
if ( increasePlayerCounts( &evt, false ) ) {
setAllConnectedTimer();
@ -660,7 +628,7 @@ CookieRef::handleEvents()
CRefMgr::Get()->IncrementFullCount();
cancelAllConnectedTimer();
sendAllHere( true );
checkSomeMissing();
/* checkSomeMissing(); */
break;
case XWA_SNDALLHERE_2:
@ -1046,29 +1014,6 @@ CookieRef::sendAllHere( bool initial )
}
} /* sendAllHere */
void
CookieRef::checkSomeMissing( void )
{
logf( XW_LOGINFO, "%s", __func__ );
/* int count = 0; */
/* vector<HostRec>::iterator iter; */
/* for ( iter = m_sockets.begin(); iter != m_sockets.end(); ++iter ) { */
/* count += iter->m_nPlayersH; */
/* } */
/* /\* Don't really need the iterator above.... *\/ */
/* assert( count == m_nPlayersHere ); */
logf( XW_LOGINFO, "%s; count=%d; nPlayersS=%d", __func__,
m_nPlayersHere, m_nPlayersSought );
assert( m_nPlayersHere <= m_nPlayersSought );
if ( m_nPlayersHere < m_nPlayersSought ) {
CRefEvent evt( XWE_SOMEMISSING );
m_eventQueue.push_back( evt );
}
}
#define CONNNAME_DELIM ' ' /* ' ' so will wrap in browser */
/* Does my seed belong as part of existing connName */
bool

View file

@ -68,9 +68,9 @@ class CookieRef {
friend class CookieMapIterator;
CookieRef( const char* cookie, const char* connName, CookieID id,
int langCode, int nPlayersH );
int langCode, int nPlayersT, int nPlayersH );
void ReInit( const char* cookie, const char* connName, CookieID id,
int langCode, int nPlayers );
int langCode, int nPlayers, int nAlreadyHere );
~CookieRef();
void Clear(void); /* make clear it's unused */
@ -94,7 +94,6 @@ class CookieRef {
int GetHeartbeat() { return m_heatbeat; }
int SocketForHost( HostID dest );
bool NeverFullyConnected();
bool AlreadyHere( unsigned short seed, int socket );
bool GameOpen( const char* cookie );

View file

@ -245,14 +245,17 @@ CRefMgr::getMakeCookieRef_locked( const char* cookie, HostID hid, int socket,
*/
char connNameBuf[MAX_CONNNAME_LEN+1] = {0};
int alreadyHere = 0;
CookieID cid = m_db->FindOpen( cookie, langCode, nPlayersT, nPlayersH,
wantsPublic,
connNameBuf, sizeof(connNameBuf) );
connNameBuf, sizeof(connNameBuf),
&alreadyHere );
if ( cid > 0 ) {
cref = getCookieRef_impl( cid );
} else {
cid = nextCID( NULL );
cref = AddNew( cookie, connNameBuf, cid, langCode, nPlayersT );
cref = AddNew( cookie, connNameBuf, cid, langCode,
nPlayersT, alreadyHere );
if ( !connNameBuf[0] ) { /* didn't exist in DB */
m_db->AddNew( cookie, cref->ConnName(), cid, langCode, nPlayersT,
wantsPublic || makePublic );
@ -274,15 +277,16 @@ CRefMgr::getMakeCookieRef_locked( const char* connName, HostID hid, int socket,
/* fetch these from DB */
char cookie[MAX_INVITE_LEN+1];
int langCode;
int nPlayersT;
int nPlayersT = 0;
int nAlreadyHere = 0;
CookieID cid = m_db->FindGame( connName, cookie, sizeof(cookie),
&langCode, &nPlayersT );
&langCode, &nPlayersT, &nAlreadyHere );
if ( 0 != cid ) { /* already open */
cref = getCookieRef_impl( cid );
} else {
CookieID cid = nextCID( NULL );
cref = AddNew( cookie, connName, cid, langCode, nPlayersT );
cref = AddNew( cookie, connName, cid, langCode, nPlayersT, nAlreadyHere );
m_db->AddCID( connName, cid );
}
return cref;
@ -435,7 +439,7 @@ CRefMgr::heartbeatProc( void* closure )
CookieRef*
CRefMgr::AddNew( const char* cookie, const char* connName, CookieID id,
int langCode, int nPlayers )
int langCode, int nPlayers, int nAlreadyHere )
{
if ( 0 == connName[0] ) {
connName = NULL;
@ -451,10 +455,11 @@ CRefMgr::AddNew( const char* cookie, const char* connName, CookieID id,
if ( !!ref ) {
logf( XW_LOGVERBOSE1, "using from free list" );
ref->ReInit( cookie, connName, id, langCode, nPlayers );
ref->ReInit( cookie, connName, id, langCode, nPlayers, nAlreadyHere );
} else {
logf( XW_LOGVERBOSE1, "calling constructor" );
ref = new CookieRef( cookie, connName, id, langCode, nPlayers );
ref = new CookieRef( cookie, connName, id, langCode, nPlayers,
nAlreadyHere );
}
ref->assignConnName();

View file

@ -151,7 +151,7 @@ class CRefMgr {
bool checkCookieRef_locked( CookieRef* cref );
CookieRef* getCookieRef_impl( CookieID cookieID );
CookieRef* AddNew( const char* cookie, const char* connName, CookieID id,
int langCode, int nPlayers );
int langCode, int nPlayers, int nAlreadyHere );
CookieRef* FindOpenGameFor( const char* cookie, const char* connName,
HostID hid, int socket, int nPlayersH,
int nPlayersS, int gameSeed, int langCode,

View file

@ -90,8 +90,8 @@ DBMgr::AddNew( const char* cookie, const char* connName, CookieID cid,
logf( XW_LOGINFO, "passing %s", buf );
execSql( buf );
#else
const char* command = "INSERT INTO games (cookie, connName, ntotal, nhere, lang) "
"VALUES( $1, $2, $3, $4, $5 )";
const char* command = "INSERT INTO games (cookie, connName, ntotal, "
"nJoined, lang) VALUES( $1, $2, $3, $4, $5 )";
char nPlayersTBuf[4];
char langBuf[4];
@ -114,11 +114,11 @@ DBMgr::AddNew( const char* cookie, const char* connName, CookieID cid,
CookieID
DBMgr::FindGame( const char* connName, char* cookieBuf, int bufLen,
int* langP, int* nPlayersTP )
int* langP, int* nPlayersTP, int* nPlayersHP )
{
CookieID cid = 0;
const char* fmt = "SELECT cid, room, lang, nTotal from " TABLE_NAME
const char* fmt = "SELECT cid, room, lang, nTotal, nJoined FROM " TABLE_NAME
" where connName = '%s' "
"LIMIT 1";
char query[256];
@ -131,6 +131,7 @@ DBMgr::FindGame( const char* connName, char* cookieBuf, int bufLen,
snprintf( cookieBuf, bufLen, "%s", PQgetvalue( result, 0, 1 ) );
*langP = atoi( PQgetvalue( result, 0, 2 ) );
*nPlayersTP = atoi( PQgetvalue( result, 0, 3 ) );
*nPlayersHP = atoi( PQgetvalue( result, 0, 4 ) );
}
PQclear( result );
@ -140,11 +141,12 @@ DBMgr::FindGame( const char* connName, char* cookieBuf, int bufLen,
CookieID
DBMgr::FindOpen( const char* cookie, int lang, int nPlayersT, int nPlayersH,
bool wantsPublic, char* connNameBuf, int bufLen )
bool wantsPublic, char* connNameBuf, int bufLen,
int* nPlayersHP )
{
CookieID cid = 0;
const char* fmt = "SELECT cid, connName FROM " TABLE_NAME " "
const char* fmt = "SELECT cid, connName, nJoined FROM " TABLE_NAME " "
"WHERE room = '%s' "
"AND lang = %d "
"AND nTotal = %d "
@ -160,6 +162,7 @@ DBMgr::FindOpen( const char* cookie, int lang, int nPlayersT, int nPlayersH,
if ( 1 == PQntuples( result ) ) {
cid = atoi( PQgetvalue( result, 0, 0 ) );
snprintf( connNameBuf, bufLen, "%s", PQgetvalue( result, 0, 1 ) );
*nPlayersHP = atoi( PQgetvalue( result, 0, 2 ) );
/* cid may be 0, but should use game anyway */
}
PQclear( result );

View file

@ -36,10 +36,10 @@ class DBMgr {
int langCode, int nPlayersT, bool isPublic );
CookieID FindGame( const char* connName, char* cookieBuf, int bufLen,
int* langP, int* nPlayersTP );
int* langP, int* nPlayersTP, int* nPlayersHP );
CookieID FindOpen( const char* cookie, int lang, int nPlayersT,
int nPlayersH, bool wantsPublic,
char* connNameBuf, int bufLen );
char* connNameBuf, int bufLen, int* nPlayersHP );
void AddPlayers( const char* const connName, int nToAdd );
void RmPlayers( const char* const connName, int nToAdd );

View file

@ -72,6 +72,7 @@ static StateTable g_stateTable[] = {
{ XWS_ALLCONND, XWE_RECONNECT, XWA_SEND_RERSP, XWS_ALLCONND },
{ XWS_ALLCONND, XWE_ALLHERE, XWA_NONE, XWS_ALLCONND },
{ XWS_ALLCONND, XWE_REMOVESOCKET, XWA_REMOVESOCK_1, XWS_ALLCONND },
/* { XWS_WAITMORE, XWE_GAMEFULL, XWA_SENDALLHERE, XWS_ALLCONND }, */
/* { XWS_WAITMORE, XWE_CHECKFULL, XWA_, XWS_WAITMORE }, */
@ -85,21 +86,25 @@ static StateTable g_stateTable[] = {
{ XWS_CHK_ALLHERE, XWE_ALLHERE, XWA_SENDALLHERE, XWS_ALLCONND },
{ XWS_ALLCONND, XWE_SOMEMISSING, XWA_NONE, XWS_MISSING },
{ XWS_CHK_ALLHERE, XWE_SOMEMISSING, XWA_NONE, XWS_WAITMORE },
/* { XWS_CHK_ALLHERE, XWE_ALLHERE, XWA_SENDALLHERE, XWS_ALLCONND }, */
/* { XWS_ALLCONND, XWE_SOMEMISSING, XWA_NONE, XWS_ALLCONND }, */
{ XWS_ALLCONND, XWE_ALLGONE, XWA_NONE, XWS_ALLCONND },
{ XWS_ALLCONND, XWE_DISCONN, XWA_DISCONNECT, XWS_MISSING },
{ XWS_WAITMORE, XWE_DISCONN, XWA_DISCONNECT, XWS_WAITMORE },
{ XWS_MISSING, XWE_DISCONN, XWA_DISCONNECT, XWS_MISSING },
/* { XWS_CHK_ALLHERE, XWE_SOMEMISSING, XWA_NONE, XWS_WAITMORE }, */
/* { XWS_ALLCONND, XWE_DISCONN, XWA_DISCONNECT, XWS_MISSING }, */
/* { XWS_WAITMORE, XWE_DISCONN, XWA_DISCONNECT, XWS_WAITMORE }, */
/* { XWS_MISSING, XWE_DISCONN, XWA_DISCONNECT, XWS_MISSING }, */
/* EMPTY means have messages to send but no connections. Time out and free
memory after a while. BUT: don't I really want to keep these forever and
free the oldest ones if memory usage realy does become a problem.
There's no problem now! */
{ XWS_WAITMORE, XWE_NOMORESOCKETS, XWA_NONE, XWS_WAITMORE },
{ XWS_MISSING, XWE_NOMORESOCKETS, XWA_NOTE_EMPTY, XWS_MSGONLY },
{ XWS_MSGONLY, XWE_NOMOREMSGS, XWA_NONE, XWS_DEAD },
/* { XWS_WAITMORE, XWE_NOMORESOCKETS, XWA_NONE, XWS_WAITMORE }, */
/* { XWS_MISSING, XWE_NOMORESOCKETS, XWA_NOTE_EMPTY, XWS_MSGONLY }, */
/* { XWS_MSGONLY, XWE_NOMOREMSGS, XWA_NONE, XWS_DEAD }, */
/* { XWS_MSGONLY, XWE_NOMOREMSGS, XWA_NONE, XWS_DEAD }, */
{ XWS_ANY, XWE_NOMORESOCKETS, XWA_NONE, XWS_DEAD },
@ -110,13 +115,13 @@ static StateTable g_stateTable[] = {
{ XWS_INITED, XWE_RECONNECT, XWA_SEND_RERSP, XWS_WAITMORE },
{ XWS_MSGONLY, XWE_RECONNECT, XWA_SEND_RERSP, XWS_WAITMORE },
{ XWS_MISSING, XWE_RECONNECT, XWA_SEND_RERSP, XWS_CHK_ALLHERE_2 },
{ XWS_CHK_ALLHERE_2, XWE_ALLHERE, XWA_SNDALLHERE_2, XWS_ALLCONND },
{ XWS_CHK_ALLHERE_2, XWE_SOMEMISSING, XWA_NONE, XWS_MISSING },
/* { XWS_MISSING, XWE_RECONNECT, XWA_SEND_RERSP, XWS_CHK_ALLHERE_2 }, */
/* { XWS_CHK_ALLHERE_2, XWE_ALLHERE, XWA_SNDALLHERE_2, XWS_ALLCONND }, */
/* { XWS_CHK_ALLHERE_2, XWE_SOMEMISSING, XWA_NONE, XWS_MISSING }, */
{ XWS_WAITMORE, XWE_REMOVESOCKET, XWA_REMOVESOCK_1, XWS_WAITMORE },
{ XWS_ALLCONND, XWE_REMOVESOCKET, XWA_REMOVESOCK_2, XWS_MISSING },
{ XWS_MISSING, XWE_REMOVESOCKET, XWA_REMOVESOCK_2, XWS_MISSING },
/* { XWS_ALLCONND, XWE_REMOVESOCKET, XWA_REMOVESOCK_2, XWS_MISSING }, */
/* { XWS_MISSING, XWE_REMOVESOCKET, XWA_REMOVESOCK_2, XWS_MISSING }, */
#ifdef RELAY_HEARTBEAT
{ XWS_ALLCONND, XWE_HEARTFAILED, XWA_HEARTDISCONN, XWS_MISSING },
@ -131,17 +136,17 @@ static StateTable g_stateTable[] = {
/* Connect timer */
{ XWS_WAITMORE, XWE_CONNTIMER, XWA_TIMERDISCONN, XWS_DEAD },
{ XWS_MISSING, XWE_CONNTIMER, XWA_NONE, XWS_MISSING },
/* { XWS_MISSING, XWE_CONNTIMER, XWA_NONE, XWS_MISSING }, */
{ XWS_ALLCONND, XWE_CONNTIMER, XWA_NONE, XWS_ALLCONND },
{ XWS_WAITMORE, XWE_NOTIFYDISCON, XWA_NOTIFYDISCON, XWS_WAITMORE },
{ XWS_ALLCONND, XWE_NOTIFYDISCON, XWA_NOTIFYDISCON, XWS_MISSING },
{ XWS_MISSING, XWE_NOTIFYDISCON, XWA_NOTIFYDISCON, XWS_MISSING },
/* { XWS_ALLCONND, XWE_NOTIFYDISCON, XWA_NOTIFYDISCON, XWS_MISSING }, */
/* { XWS_MISSING, XWE_NOTIFYDISCON, XWA_NOTIFYDISCON, XWS_MISSING }, */
{ XWS_DEAD, XWE_NOTIFYDISCON, XWA_NOTIFYDISCON, XWS_DEAD },
/* This is our bread-n-butter */
{ XWS_ALLCONND, XWE_FORWARDMSG, XWA_FWD, XWS_ALLCONND },
{ XWS_MISSING, XWE_FORWARDMSG, XWA_FWD, XWS_MISSING },
/* { XWS_MISSING, XWE_FORWARDMSG, XWA_FWD, XWS_MISSING }, */
{ XWS_DEAD, XWE_REMOVESOCKET, XWA_REMOVESOCK_1, XWS_DEAD }
@ -184,12 +189,12 @@ stateString( XW_RELAY_STATE state )
CASESTR(XWS_WAITING_ACKS);
CASESTR(XWS_ALLCONND);
CASESTR(XWS_DEAD);
CASESTR(XWS_MISSING);
/* CASESTR(XWS_MISSING); */
CASESTR(XWS_MSGONLY);
CASESTR(XWS_CHK_ALLHERE);
CASESTR(XWS_CHK_ALLHERE_2);
CASESTR(XWS_CHKCOUNTS_INIT);
CASESTR(XWS_ROOMCHK);
/* CASESTR(XWS_CHK_ALLHERE); */
/* CASESTR(XWS_CHK_ALLHERE_2); */
/* CASESTR(XWS_CHKCOUNTS_INIT); */
/* CASESTR(XWS_ROOMCHK); */
default:
assert(0);
}
@ -224,9 +229,9 @@ eventString( XW_RELAY_EVENT evt )
CASESTR(XWE_NOMOREMSGS);
CASESTR(XWE_NOTIFYDISCON);
CASESTR(XWE_ALLHERE);
CASESTR(XWE_SOMEMISSING);
CASESTR(XWE_TOO_MANY);
CASESTR(XWE_HAVE_ROOM);
/* CASESTR(XWE_SOMEMISSING); */
/* CASESTR(XWE_TOO_MANY); */
/* CASESTR(XWE_HAVE_ROOM); */
CASESTR(XWE_SHUTDOWN);
default:

View file

@ -28,16 +28,16 @@ enum {
XWS_NONE
,XWS_ANY /* wildcard */
,XWS_CHKCOUNTS_INIT /* from initial state, check if all players
/* ,XWS_CHKCOUNTS_INIT */ /* from initial state, check if all players
are here. Success should be an error,
actually: 1-device game. */
,XWS_WAITING_ACKS
,XWS_CHK_ALLHERE /* Need to see if all expected devices/players
/* ,XWS_CHK_ALLHERE */ /* Need to see if all expected devices/players
are on board. */
,XWS_CHK_ALLHERE_2 /* same as above, but triggered by a reconnect
/* ,XWS_CHK_ALLHERE_2 */ /* same as above, but triggered by a reconnect
rather than a connect request */
,XWS_INITED /* Relay's running and the object's been
@ -54,14 +54,14 @@ enum {
relay to do its work. This is the state
we're in most of the time. */
,XWS_MISSING /* We've been fully connected before but lost
/* ,XWS_MISSING */ /* We've been fully connected before but lost
somebody. Once [s]he's back we can be
fully connected again. */
,XWS_MSGONLY /* We have no connections but still messages to
send */
,XWS_ROOMCHK /* do we have room for as many players as are
/* ,XWS_ROOMCHK */ /* do we have room for as many players as are
being provided */
,XWS_DEAD /* About to kill the object */
@ -73,9 +73,10 @@ typedef enum {
XWE_NONE
,XWE_ALLHERE /* notify that all expected players are arrived */
,XWE_SOMEMISSING /* notify that some expected players are still missing */
,XWE_HAVE_ROOM
,XWE_TOO_MANY
/* ,XWE_SOMEMISSING */ /* notify that some expected players are still missing */
,XWE_ALLGONE
/* ,XWE_HAVE_ROOM */
/* ,XWE_TOO_MANY */
,XWE_DEVCONNECT /* A device is connecting using the cookie for */
/*,XWE_HOSTCONNECT*/ /* this object, as host or guest */