From 50c387d75e4cf0d33d80f3516800d6e4d42bdc9f Mon Sep 17 00:00:00 2001 From: Andy2 Date: Thu, 16 Sep 2010 06:49:35 -0700 Subject: [PATCH 1/4] remove players from db as well as runtime when ack times out --- xwords4/relay/cref.cpp | 1 + xwords4/relay/dbmgr.cpp | 6 ++++++ xwords4/relay/dbmgr.h | 1 + 3 files changed, 8 insertions(+) diff --git a/xwords4/relay/cref.cpp b/xwords4/relay/cref.cpp index 43ceaebc8..eb83f60ed 100644 --- a/xwords4/relay/cref.cpp +++ b/xwords4/relay/cref.cpp @@ -826,6 +826,7 @@ CookieRef::modPending( const CRefEvent* evt, bool keep ) if ( keep ) { iter->m_ackPending = false; } else { + DBMgr::Get()->RmPlayers( ConnName(), iter->m_nPlayersH ); m_sockets.erase( iter ); } break; diff --git a/xwords4/relay/dbmgr.cpp b/xwords4/relay/dbmgr.cpp index 446f74ba4..9e86c700f 100644 --- a/xwords4/relay/dbmgr.cpp +++ b/xwords4/relay/dbmgr.cpp @@ -179,6 +179,12 @@ DBMgr::AddPlayers( const char* connName, int nToAdd ) execSql( query ); } +void +DBMgr::RmPlayers( const char* connName, int nToAdd ) +{ + AddPlayers( connName, 0 - nToAdd ); +} + void DBMgr::AddCID( const char* const connName, CookieID cid ) { diff --git a/xwords4/relay/dbmgr.h b/xwords4/relay/dbmgr.h index aecb23253..79aa6310f 100644 --- a/xwords4/relay/dbmgr.h +++ b/xwords4/relay/dbmgr.h @@ -42,6 +42,7 @@ class DBMgr { char* connNameBuf, int bufLen ); void AddPlayers( const char* const connName, int nToAdd ); + void RmPlayers( const char* const connName, int nToAdd ); void AddCID( const char* connName, CookieID cid ); void ClearCID( const char* connName ); From 76e7459a6d0df8a65cdb7519fb694af83e1da33c Mon Sep 17 00:00:00 2001 From: Andy2 Date: Thu, 16 Sep 2010 18:56:34 -0700 Subject: [PATCH 2/4] various improvements, e.g. random sleeps before and after starting --- xwords4/linux/scripts/discon_ok2.sh | 40 +++++++++++++++++++++++++---- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/xwords4/linux/scripts/discon_ok2.sh b/xwords4/linux/scripts/discon_ok2.sh index 2452c1348..bae2c3061 100755 --- a/xwords4/linux/scripts/discon_ok2.sh +++ b/xwords4/linux/scripts/discon_ok2.sh @@ -1,5 +1,24 @@ #!/bin/bash +NGAMES=${NGAMES:-1} + +USE_GTK=${USE_GTK:-FALSE} + +if [ $USE_GTK = FALSE ]; then + PLAT_PARMS="-u -0" +else + PLAT_PARMS="-z 1:10" +fi + +usage() { + echo "usage: [env=val *] $0" 1>&2 + echo " current env variables and their values: " 1>&2 + for VAR in NGAMES; do + echo "$VAR:" $(eval "echo \$${VAR}") 1>&2 + done + exit 0 +} + do_device() { GAME=$1 DEV=$2 @@ -13,14 +32,15 @@ do_device() { done while :; do + sleep $((RANDOM%5)) ./obj_linux_memdbg/xwords -C foo -r edd $OTHERS \ - -d dict.xwd -f $FILE 2>>$LOG & + -d dict.xwd -f $FILE $PLAT_PARMS >/dev/null 2>>$LOG & PID=$! - sleep $((RANDOM%5+1)) - kill $PID + sleep $((RANDOM%10+10)) + kill $PID 2>/dev/null [ $(grep -c 'all remaining tiles' $LOG) -eq $NDEVS ] && break - pidof xwrelay || break + pidof xwrelay > /dev/null || break done } @@ -36,6 +56,16 @@ do_game() { done } -for GAME in $(seq 1 1); do +while [ -n "$1" ]; do + case $1 in + *) usage + ;; + esac + shift +done + +for GAME in $(seq 1 $NGAMES); do do_game $GAME done + +wait From 1490b2def913606e4c09d8fd14cf107de3d3d851 Mon Sep 17 00:00:00 2001 From: Andy2 Date: Thu, 16 Sep 2010 18:59:56 -0700 Subject: [PATCH 3/4] 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. --- xwords4/relay/cref.cpp | 65 +++------------------------------------ xwords4/relay/cref.h | 5 ++- xwords4/relay/crefmgr.cpp | 21 ++++++++----- xwords4/relay/crefmgr.h | 2 +- xwords4/relay/dbmgr.cpp | 15 +++++---- xwords4/relay/dbmgr.h | 4 +-- xwords4/relay/states.cpp | 57 ++++++++++++++++++---------------- xwords4/relay/states.h | 17 +++++----- 8 files changed, 72 insertions(+), 114 deletions(-) diff --git a/xwords4/relay/cref.cpp b/xwords4/relay/cref.cpp index eb83f60ed..d888e6398 100644 --- a/xwords4/relay/cref.cpp +++ b/xwords4/relay/cref.cpp @@ -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::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 diff --git a/xwords4/relay/cref.h b/xwords4/relay/cref.h index c855f62b0..e85150b75 100644 --- a/xwords4/relay/cref.h +++ b/xwords4/relay/cref.h @@ -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 ); diff --git a/xwords4/relay/crefmgr.cpp b/xwords4/relay/crefmgr.cpp index 18186af49..736a49e12 100644 --- a/xwords4/relay/crefmgr.cpp +++ b/xwords4/relay/crefmgr.cpp @@ -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(); diff --git a/xwords4/relay/crefmgr.h b/xwords4/relay/crefmgr.h index 74e921f87..4c646d42e 100644 --- a/xwords4/relay/crefmgr.h +++ b/xwords4/relay/crefmgr.h @@ -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, diff --git a/xwords4/relay/dbmgr.cpp b/xwords4/relay/dbmgr.cpp index 9e86c700f..cb5bfb2e0 100644 --- a/xwords4/relay/dbmgr.cpp +++ b/xwords4/relay/dbmgr.cpp @@ -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 ); diff --git a/xwords4/relay/dbmgr.h b/xwords4/relay/dbmgr.h index 79aa6310f..f34bea367 100644 --- a/xwords4/relay/dbmgr.h +++ b/xwords4/relay/dbmgr.h @@ -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 ); diff --git a/xwords4/relay/states.cpp b/xwords4/relay/states.cpp index d510d3000..00244b480 100644 --- a/xwords4/relay/states.cpp +++ b/xwords4/relay/states.cpp @@ -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: diff --git a/xwords4/relay/states.h b/xwords4/relay/states.h index f5156827d..8d6175622 100644 --- a/xwords4/relay/states.h +++ b/xwords4/relay/states.h @@ -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 */ From c5eef29bcc87a38df612c52d6d1d55d142905a18 Mon Sep 17 00:00:00 2001 From: Andy2 Date: Thu, 16 Sep 2010 20:08:32 -0700 Subject: [PATCH 4/4] some suspicious crashes and subsequent reading say that multiple threads can't share the same db connection. So synchronize all queries. Multiple threads *can* access the db concurrently as long as each has its own connection, so I could add connections to the tpool threads. But this will probably be performant enough for the first 10K simultaneous users. :-) --- xwords4/relay/dbmgr.cpp | 13 ++++++++++--- xwords4/relay/dbmgr.h | 2 +- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/xwords4/relay/dbmgr.cpp b/xwords4/relay/dbmgr.cpp index cb5bfb2e0..b0b46b9b2 100644 --- a/xwords4/relay/dbmgr.cpp +++ b/xwords4/relay/dbmgr.cpp @@ -22,6 +22,7 @@ #include #include "dbmgr.h" +#include "mlock.h" #include "xwrelay_priv.h" #define DB_NAME "xwgames" @@ -50,6 +51,8 @@ DBMgr::DBMgr() exit( 1 ); } + pthread_mutex_init( &m_dbMutex, NULL ); + /* Now figure out what the largest cid currently is. There must be a way to get postgres to do this for me.... */ /* const char* query = "SELECT cid FROM games ORDER BY cid DESC LIMIT 1"; */ @@ -125,6 +128,8 @@ DBMgr::FindGame( const char* connName, char* cookieBuf, int bufLen, snprintf( query, sizeof(query), fmt, connName ); logf( XW_LOGINFO, "query: %s", query ); + MutexLock ml( &m_dbMutex ); + PGresult* result = PQexec( m_pgconn, query ); if ( 1 == PQntuples( result ) ) { cid = atoi( PQgetvalue( result, 0, 0 ) ); @@ -158,6 +163,8 @@ DBMgr::FindOpen( const char* cookie, int lang, int nPlayersT, int nPlayersH, cookie, lang, nPlayersT, nPlayersH, wantsPublic?"TRUE":"FALSE" ); logf( XW_LOGINFO, "query: %s", query ); + MutexLock ml( &m_dbMutex ); + PGresult* result = PQexec( m_pgconn, query ); if ( 1 == PQntuples( result ) ) { cid = atoi( PQgetvalue( result, 0, 0 ) ); @@ -221,13 +228,13 @@ DBMgr::ClearCIDs( void ) void DBMgr::execSql( const char* query ) { + MutexLock ml( &m_dbMutex ); PGresult* result = PQexec( m_pgconn, query ); if ( PGRES_COMMAND_OK != PQresultStatus(result) ) { - logf( XW_LOGERROR, "PQEXEC=>%s", PQresultErrorMessage(result) ); - assert( 0 ); + logf( XW_LOGERROR, "PQexec=>%s", PQresStatus(PQresultStatus(result) )); + logf( XW_LOGERROR, "PQexec=>%s", PQresultErrorMessage(result) ); } PQclear( result ); - logf( XW_LOGINFO, "PQexecParams=>%d", result ); } /* diff --git a/xwords4/relay/dbmgr.h b/xwords4/relay/dbmgr.h index f34bea367..621333ab4 100644 --- a/xwords4/relay/dbmgr.h +++ b/xwords4/relay/dbmgr.h @@ -50,7 +50,7 @@ class DBMgr { DBMgr(); void execSql( const char* query ); /* no-results query */ PGconn* m_pgconn; - //int m_nextCID; + pthread_mutex_t m_dbMutex; }; /* DBMgr */