|
From: <gne...@us...> - 2007-10-26 23:14:23
|
Update of /cvsroot/aolserver/aolserver/nsd In directory sc8-pr-cvs11.sourceforge.net:/tmp/cvs-serv25463 Modified Files: nsd.h pools.c queue.c Log Message: Keep track of connection thread state. Two new variables are introduced: - starting: keeps the number of currently starting threads - waiting: the number of threads in the cond waiting state These variables help to get a more precise understanding and allow for better knowlege for thread creation (especially under heavy load) Index: nsd.h =================================================================== RCS file: /cvsroot/aolserver/aolserver/nsd/nsd.h,v retrieving revision 1.118 retrieving revision 1.119 diff -C2 -d -r1.118 -r1.119 *** nsd.h 20 Oct 2007 11:57:19 -0000 1.118 --- nsd.h 26 Oct 2007 23:14:17 -0000 1.119 *************** *** 565,568 **** --- 565,570 ---- int current; int idle; + int waiting; + int starting; int timeout; int maxconns; Index: pools.c =================================================================== RCS file: /cvsroot/aolserver/aolserver/nsd/pools.c,v retrieving revision 1.11 retrieving revision 1.12 diff -C2 -d -r1.11 -r1.12 *** pools.c 20 Oct 2007 11:57:19 -0000 1.11 --- pools.c 26 Oct 2007 23:14:17 -0000 1.12 *************** *** 185,188 **** --- 185,201 ---- } } + /* catch unsane values */ + if (poolPtr->threads.max < 1) { + Tcl_SetResult(interp, "maxthreads can't be less than 1", TCL_STATIC); + return TCL_ERROR; + } + if (poolPtr->threads.min > poolPtr->threads.max) { + Tcl_SetResult(interp, "minthreads can't be larger than maxthreads", TCL_STATIC); + return TCL_ERROR; + } + if (poolPtr->threads.timeout < 1) { + Tcl_SetResult(interp, "timeout cannot be less than 1", TCL_STATIC); + return TCL_ERROR; + } if (PoolResult(interp, poolPtr) != TCL_OK) { return TCL_ERROR; *************** *** 480,485 **** int i; ! poolPtr->threads.current = poolPtr->threads.idle = poolPtr->threads.min; for (i = 0; i < poolPtr->threads.min; ++i) { NsCreateConnThread(poolPtr, 1); } --- 493,503 ---- int i; ! poolPtr->threads.current = 0; ! poolPtr->threads.starting = 0; ! poolPtr->threads.waiting = 0; ! poolPtr->threads.idle = 0; ! for (i = 0; i < poolPtr->threads.min; ++i) { + poolPtr->threads.current ++; NsCreateConnThread(poolPtr, 1); } Index: queue.c =================================================================== RCS file: /cvsroot/aolserver/aolserver/nsd/queue.c,v retrieving revision 1.43 retrieving revision 1.44 diff -C2 -d -r1.43 -r1.44 *** queue.c 22 Oct 2007 22:56:23 -0000 1.43 --- queue.c 26 Oct 2007 23:14:17 -0000 1.44 *************** *** 179,203 **** poolPtr->queue.wait.lastPtr = connPtr; connPtr->nextPtr = NULL; ! if (poolPtr->threads.idle == 0 ! && poolPtr->threads.current < poolPtr->threads.max) { ! ++poolPtr->threads.idle; ! ++poolPtr->threads.current; create = 1; } ! /* ! Note that in situations, where the maximum number of ! connection threads is reached (poolPtr->threads.idle == 0 and create == 0) ! the request is queued without resources to process these. ! One has to take care about processing he entries of the queue, when ! resources become available again. ! */ ! ! ++poolPtr->queue.wait.num; ! Ns_MutexUnlock(&poolPtr->lock); if (create) { NsCreateConnThread(poolPtr, 1); ! } else { Ns_CondSignal(&poolPtr->cond); } } --- 179,213 ---- poolPtr->queue.wait.lastPtr = connPtr; connPtr->nextPtr = NULL; ! ! if (poolPtr->queue.wait.num > 0 ! && poolPtr->threads.current < poolPtr->threads.max) { ! /* ! Create a new thread if no thread is waiting and the number ! of currently starting or running threads is below max. ! */ create = 1; } ! poolPtr->queue.wait.num ++; ! if (create) { + poolPtr->threads.current ++; + Ns_MutexUnlock(&poolPtr->lock); NsCreateConnThread(poolPtr, 1); ! } else if (poolPtr->threads.waiting > 0) { ! /* ! There are threads waiting. Signal to process ! the request. ! */ Ns_CondSignal(&poolPtr->cond); + Ns_MutexUnlock(&poolPtr->lock); + } else { + /* + We might have missed signaling, since we are already using + max resources, and no thread is available. In such a case + the autorecovery at thread exist has to care to process + the outstanding requests + */ + Ns_MutexUnlock(&poolPtr->lock); } } *************** *** 379,382 **** --- 389,396 ---- Ns_MutexLock(&poolPtr->lock); + + poolPtr->threads.starting--; + poolPtr->threads.idle++; + while (poolPtr->threads.maxconns <= 0 || ncons-- > 0) { *************** *** 385,389 **** * arrive in the configured timeout period. */ ! if (poolPtr->threads.current <= poolPtr->threads.min) { timePtr = NULL; --- 399,403 ---- * arrive in the configured timeout period. */ ! if (poolPtr->threads.current <= poolPtr->threads.min) { timePtr = NULL; *************** *** 394,398 **** } ! status = NS_OK; while (!poolPtr->shutdown && status == NS_OK --- 408,412 ---- } ! status = NS_OK; while (!poolPtr->shutdown && status == NS_OK *************** *** 401,405 **** --- 415,421 ---- nothing is queued, we wait for a queue entry */ + poolPtr->threads.waiting++; status = Ns_CondTimedWait(&poolPtr->cond, &poolPtr->lock, timePtr); + poolPtr->threads.waiting--; } *************** *** 420,510 **** connPtr->nextPtr = NULL; connPtr->prevPtr = poolPtr->queue.active.lastPtr; ! if (poolPtr->queue.active.lastPtr != NULL) { ! poolPtr->queue.active.lastPtr->nextPtr = connPtr; ! } ! poolPtr->queue.active.lastPtr = connPtr; ! if (poolPtr->queue.active.firstPtr == NULL) { ! poolPtr->queue.active.firstPtr = connPtr; ! } ! poolPtr->threads.idle--; ! poolPtr->queue.wait.num--; ! Ns_MutexUnlock(&poolPtr->lock); ! ! /* ! * Run the connection. ! */ ! ! Ns_MutexLock(&connlock); ! dataPtr->connPtr = connPtr; ! Ns_MutexUnlock(&connlock); ! Ns_GetTime(&connPtr->times.run); ! ConnRun(connPtr); ! Ns_MutexLock(&connlock); ! dataPtr->connPtr = NULL; ! Ns_MutexUnlock(&connlock); ! /* ! * Remove from the active list and push on the free list. ! */ ! Ns_MutexLock(&poolPtr->lock); ! if (connPtr->prevPtr != NULL) { ! connPtr->prevPtr->nextPtr = connPtr->nextPtr; ! } else { ! poolPtr->queue.active.firstPtr = connPtr->nextPtr; ! } ! if (connPtr->nextPtr != NULL) { ! connPtr->nextPtr->prevPtr = connPtr->prevPtr; ! } else { ! poolPtr->queue.active.lastPtr = connPtr->prevPtr; ! } ! poolPtr->threads.idle++; ! Ns_MutexUnlock(&poolPtr->lock); ! NsFreeConn(connPtr); ! Ns_MutexLock(&poolPtr->lock); } ! /* * Append this thread to list of threads to reap. */ ! Ns_MutexLock(&joinlock); dataPtr->nextPtr = joinPtr; joinPtr = dataPtr; Ns_MutexUnlock(&joinlock); ! /* * Mark this thread as no longer active. */ ! if (poolPtr->shutdown) { ! msg = "shutdown pending"; } - poolPtr->threads.idle--; poolPtr->threads.current--; ! if (poolPtr->threads.current == 0) { ! Ns_CondBroadcast(&poolPtr->cond); ! } ! ! if (((poolPtr->queue.wait.num > 0 && poolPtr->threads.idle == 0) || (poolPtr->threads.current < poolPtr->threads.min) ) && !poolPtr->shutdown) { /* ! We are either exiting from a thread in a situation, where more ! queue entries are still waiting, or ! we have less than minthreads connection threads alive. ! In these situations recreate a connection thread. */ ! poolPtr->threads.current++; ! poolPtr->threads.idle++; Ns_MutexUnlock(&poolPtr->lock); NsCreateConnThread(poolPtr, 0); /* joinThreads == 0 to avoid deadlock */ } else { Ns_MutexUnlock(&poolPtr->lock); } ! Ns_Log(Notice, "exiting: %s", msg); Ns_ThreadExit(dataPtr); --- 436,530 ---- connPtr->nextPtr = NULL; connPtr->prevPtr = poolPtr->queue.active.lastPtr; ! if (poolPtr->queue.active.lastPtr != NULL) { ! poolPtr->queue.active.lastPtr->nextPtr = connPtr; ! } ! poolPtr->queue.active.lastPtr = connPtr; ! if (poolPtr->queue.active.firstPtr == NULL) { ! poolPtr->queue.active.firstPtr = connPtr; ! } ! poolPtr->threads.idle--; ! poolPtr->queue.wait.num--; ! Ns_MutexUnlock(&poolPtr->lock); ! /* ! * Run the connection. ! */ ! Ns_MutexLock(&connlock); ! dataPtr->connPtr = connPtr; ! Ns_MutexUnlock(&connlock); ! ! Ns_GetTime(&connPtr->times.run); ! ConnRun(connPtr); ! Ns_MutexLock(&connlock); ! dataPtr->connPtr = NULL; ! Ns_MutexUnlock(&connlock); ! ! /* ! * Remove from the active list and push on the free list. ! */ ! Ns_MutexLock(&poolPtr->lock); ! if (connPtr->prevPtr != NULL) { ! connPtr->prevPtr->nextPtr = connPtr->nextPtr; ! } else { ! poolPtr->queue.active.firstPtr = connPtr->nextPtr; ! } ! if (connPtr->nextPtr != NULL) { ! connPtr->nextPtr->prevPtr = connPtr->prevPtr; ! } else { ! poolPtr->queue.active.lastPtr = connPtr->prevPtr; ! } ! poolPtr->threads.idle++; ! Ns_MutexUnlock(&poolPtr->lock); ! NsFreeConn(connPtr); ! Ns_MutexLock(&poolPtr->lock); } ! /* * Append this thread to list of threads to reap. */ ! Ns_MutexLock(&joinlock); dataPtr->nextPtr = joinPtr; joinPtr = dataPtr; Ns_MutexUnlock(&joinlock); ! /* * Mark this thread as no longer active. */ ! if (poolPtr->shutdown) { ! msg = "shutdown pending"; } poolPtr->threads.current--; ! poolPtr->threads.idle--; ! if (((poolPtr->queue.wait.num > 0 ! && poolPtr->threads.idle == 0 ! && poolPtr->threads.starting == 0 ! ) || (poolPtr->threads.current < poolPtr->threads.min) ) && !poolPtr->shutdown) { /* ! Recreate a thread when on of the condings hold ! - there are more queue entries are still waiting, ! but no thread is either starting or idle, or ! - there are less than minthreads connection threads alive. */ ! poolPtr->threads.current ++; Ns_MutexUnlock(&poolPtr->lock); NsCreateConnThread(poolPtr, 0); /* joinThreads == 0 to avoid deadlock */ + } else if (poolPtr->queue.wait.num > 0 && poolPtr->threads.waiting > 0) { + /* + Wake up a waiting thread + */ + Ns_CondSignal(&poolPtr->cond); + Ns_MutexUnlock(&poolPtr->lock); } else { Ns_MutexUnlock(&poolPtr->lock); } ! Ns_Log(Notice, "exiting: %s", msg); Ns_ThreadExit(dataPtr); *************** *** 669,672 **** --- 689,695 ---- dataPtr->poolPtr = poolPtr; dataPtr->connPtr = NULL; + Ns_MutexLock(&poolPtr->lock); + poolPtr->threads.starting ++; + Ns_MutexUnlock(&poolPtr->lock); Ns_ThreadCreate(NsConnThread, dataPtr, 0, &dataPtr->thread); } |