708 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			708 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
#include "gb-include.h"
 | 
						|
 | 
						|
#include <errno.h>
 | 
						|
#include "Stats.h"
 | 
						|
//#define X_DISPLAY_MISSING 1
 | 
						|
//#include <plotter.h>
 | 
						|
#include <math.h>
 | 
						|
#include "Conf.h"
 | 
						|
#include "PingServer.h"
 | 
						|
//#include "Statsdb.h"
 | 
						|
 | 
						|
class Stats g_stats;
 | 
						|
 | 
						|
// just clear our points array when we're born
 | 
						|
Stats::Stats ( ) { 
 | 
						|
	//m_gotLock            = false;
 | 
						|
	m_next               = 0;
 | 
						|
	//m_minWindowStartTime = 0;
 | 
						|
	memset ( m_pts , 0 , sizeof(StatPoint)*MAX_POINTS );
 | 
						|
 | 
						|
	//m_readSignals = 0;
 | 
						|
	//m_writeSignals = 0;
 | 
						|
	m_slowDiskReads = 0;
 | 
						|
	m_queryTimes = 0;
 | 
						|
	m_numQueries = 0;
 | 
						|
	m_numSuccess = 0;
 | 
						|
	m_numFails   = 0;
 | 
						|
	m_avgQueryTime = 0;
 | 
						|
	m_successRate = 1.0;
 | 
						|
	m_totalNumQueries = 0;
 | 
						|
	m_totalNumSuccess = 0;
 | 
						|
	m_totalNumFails   = 0;
 | 
						|
	m_avgQueriesPerSec = 0;
 | 
						|
	m_lastQueryLogTime = gettimeofdayInMilliseconds();
 | 
						|
	m_startTime = m_lastQueryLogTime;
 | 
						|
        m_upTime = 0;
 | 
						|
	m_closedSockets = 0;
 | 
						|
	m_spiderSample = 0;
 | 
						|
	m_spiderErrors = 0;
 | 
						|
	m_spiderNew = 0;
 | 
						|
	m_spiderErrorsNew = 0;
 | 
						|
	m_totalSpiderSuccessNew = 0;
 | 
						|
	m_totalSpiderErrorsNew = 0;
 | 
						|
	m_totalSpiderSuccessOld = 0;
 | 
						|
	m_totalSpiderErrorsOld = 0;
 | 
						|
	m_msg3aRecallCnt = 0;
 | 
						|
	// m_tierHits[0] = 0;
 | 
						|
	// m_tierHits[1] = 0;
 | 
						|
	// m_tierHits[2] = 0;
 | 
						|
	// m_tier2Misses = 0;
 | 
						|
	// m_tierTimes[0] = 0;
 | 
						|
	// m_tierTimes[1] = 0;
 | 
						|
	// m_tierTimes[2] = 0;
 | 
						|
	//m_totalDedupCand = 0;
 | 
						|
	//m_dedupedCand = 0;
 | 
						|
	//m_bannedDups = 0;
 | 
						|
	//m_bigHackDups = 0;
 | 
						|
	//m_summaryDups = 0;
 | 
						|
	//m_contentDups = 0;
 | 
						|
	//m_clusteredTier1 = 0;
 | 
						|
	//m_clusteredTier2 = 0;
 | 
						|
	//m_errored = 0;
 | 
						|
	m_msg3aRecalls[0] = 0;
 | 
						|
	m_msg3aRecalls[1] = 0;
 | 
						|
	m_msg3aRecalls[2] = 0;
 | 
						|
	m_msg3aRecalls[3] = 0;
 | 
						|
	m_msg3aRecalls[4] = 0;
 | 
						|
	m_msg3aRecalls[5] = 0;
 | 
						|
 | 
						|
	memset(m_errCodes, 0, 1000*4);
 | 
						|
	memset(m_isSampleNew, 0, 1000);
 | 
						|
	memset(m_allErrorsNew, 0, 65536*8);
 | 
						|
	memset(m_allErrorsOld, 0, 65536*8);
 | 
						|
	clearMsgStats();
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
void Stats::clearMsgStats() {
 | 
						|
	char *start = &m_start;
 | 
						|
	char *end   = &m_end;
 | 
						|
	memset ( start , 0 , end - start );
 | 
						|
}
 | 
						|
 | 
						|
//static pthread_mutex_t s_lock = PTHREAD_MUTEX_INITIALIZER;
 | 
						|
 | 
						|
void Stats::addStat_r ( int32_t        numBytes    , 
 | 
						|
			int64_t   startTime   ,
 | 
						|
			int64_t   endTime     ,
 | 
						|
			int32_t        color       ,
 | 
						|
			char        type        ,
 | 
						|
			char *fname) {
 | 
						|
 | 
						|
	// lock up
 | 
						|
	//pthread_mutex_lock ( &s_lock );
 | 
						|
	// . is there a point in slot we're about to occupy?
 | 
						|
	// . we might have to advance the min time for the graph window
 | 
						|
	//   so we don't exclude any disk reads/writes in the beginning
 | 
						|
	//if ( m_pts [ m_next ].m_startTime > 0                    &&
 | 
						|
	//     m_pts [ m_next ].m_endTime   > m_minWindowStartTime   )
 | 
						|
	//		m_minWindowStartTime = m_pts[m_next].m_endTime;
 | 
						|
	// claim next before another thread does
 | 
						|
	int32_t n = m_next++;
 | 
						|
	// watch out if another thread just inc'ed n
 | 
						|
	if ( n >= MAX_POINTS ) n = 0;
 | 
						|
	// stick our point in the array
 | 
						|
	StatPoint *p = & m_pts [ n ];
 | 
						|
	p->m_numBytes  = numBytes;
 | 
						|
	p->m_startTime = startTime ;
 | 
						|
	p->m_endTime   = endTime;
 | 
						|
	p->m_color     = color;
 | 
						|
	p->m_type      = type;
 | 
						|
 | 
						|
	if(fname) {
 | 
						|
		if(m_keyCols.length() > 512) m_keyCols.reset();
 | 
						|
		p->m_color     = hash32n(fname);
 | 
						|
		p->m_color &= 0xffffff;
 | 
						|
		m_keyCols.safePrintf(""
 | 
						|
				     "<td bgcolor=#%x>"
 | 
						|
				     "   </td>"
 | 
						|
				     "<td> %s "
 | 
						|
				     "</td>"
 | 
						|
				     "", p->m_color,fname);
 | 
						|
	}
 | 
						|
	// we may be the first point
 | 
						|
	//if ( m_minWindowStartTime == 0 ) m_minWindowStartTime = startTime;
 | 
						|
	// this too
 | 
						|
	//if (startTime <m_minWindowStartTime ) m_minWindowStartTime=startTime;
 | 
						|
	// advance the next available slot ptr, wrap if necessary
 | 
						|
	if ( m_next >= MAX_POINTS ) m_next = 0;
 | 
						|
 | 
						|
	// add it to statsdb now too!
 | 
						|
	//g_statsdb.addStat ( label, startTime,endTime, numBytes );
 | 
						|
 | 
						|
	// unlock
 | 
						|
	//pthread_mutex_unlock ( &s_lock );
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
// . dump a graph to /tmp/diskGraph.gif
 | 
						|
// . use libplotter.a or .so ?
 | 
						|
// . docs at http://www.gnu.org/manual/plotutils/html_mono/plotutils.html#SEC54
 | 
						|
void Stats::dumpGIF ( int64_t startTime , int64_t endTime ) {
 | 
						|
 | 
						|
	char fname [ 1024 ];
 | 
						|
	sprintf ( fname , "%s/diskGraph%" INT32 ".gif" ,
 | 
						|
		  g_hostdb.m_httpRootDir , g_hostdb.m_hostId );
 | 
						|
	FILE *fd = fopen ( fname,"w" );
 | 
						|
	if ( ! fd ) { 
 | 
						|
		log("admin: Stats::dumpGraph: fopen ( %s , \"w\" ) : %s", 
 | 
						|
		    fname , mstrerror(errno) );
 | 
						|
		return;
 | 
						|
	}
 | 
						|
	//FILE *fde = fopen ("/tmp/diskGraphError","w" );
 | 
						|
	//if ( ! fde ) { 
 | 
						|
	//	log("Stats::dumpGraph: /tmp/diskGraphError: %s", 
 | 
						|
	//	    mstrerror(errno) );
 | 
						|
	//	return;
 | 
						|
	//}
 | 
						|
	
 | 
						|
	// add some test stats
 | 
						|
	//addStat_r ( 100 , true , gettimeofdayInMilliseconds() - 10 ,
 | 
						|
	//	  gettimeofdayInMilliseconds() -3 );
 | 
						|
	//addStat_r ( 2*1024*1024 , true , gettimeofdayInMilliseconds() - 5 ,
 | 
						|
	//	  gettimeofdayInMilliseconds() );
 | 
						|
 | 
						|
	// plotter uses malloc, so we must get the lock from Mem.cpp
 | 
						|
	//mutexLock();
 | 
						|
	//m_gotLock = true;
 | 
						|
 | 
						|
	// gif size
 | 
						|
	char tmp[64];
 | 
						|
	sprintf ( tmp , "%" INT32 "x%" INT32 "", (int32_t)DX+40 , (int32_t)DY+40 ); // "1040x440"
 | 
						|
 | 
						|
#ifdef _USEPLOTTER_
 | 
						|
 | 
						|
	GIFPlotter::parampl ( "BITMAPSIZE" , (void *)tmp );
 | 
						|
	//int dx = 1000;
 | 
						|
	//int dy = 400;
 | 
						|
	// 20 pixel borders
 | 
						|
	int bx = 10;
 | 
						|
	int by = 30;
 | 
						|
	// create one
 | 
						|
	GIFPlotter plotter ( NULL , fd , NULL );
 | 
						|
	// open it
 | 
						|
	plotter.openpl ( );
 | 
						|
	// define the space with boundaries 100 unit wide boundaries
 | 
						|
	plotter.space ( -bx , -by , DX + bx , DY + by );
 | 
						|
	// line thickness in user coordinates (pixels for us)
 | 
						|
	plotter.linewidth ( 1 );       
 | 
						|
	// set bg color to gray (r/g/b) 
 | 
						|
	plotter.bgcolor ( 0xd600 , 0xce00 , 0xd600 );
 | 
						|
	// set bg color to white (r/g/b) 
 | 
						|
	//plotter.bgcolor ( 0xff00 , 0xff00 , 0xff00 );
 | 
						|
	// erase Plotter's graphics display
 | 
						|
	plotter.erase ();                
 | 
						|
	// draw axises in black
 | 
						|
	plotter.pencolorname ("black");    
 | 
						|
	// draw the x-axis
 | 
						|
	plotter.line ( 0 , 0 , DX , 0  );
 | 
						|
	// draw the y-axis
 | 
						|
	plotter.line ( 0 , 0 ,  0 , DY );
 | 
						|
	// x-axis label
 | 
						|
	//plotter.move       ( DX / 2 , -by / 2 );
 | 
						|
	//plotter.alabel     ( 'c' , 'c' , "disk accesses" );
 | 
						|
	// y-axis lavel
 | 
						|
	//plotter.move      ( x1 - bx / 2   , y1 + dy / 2 );
 | 
						|
	//plotter.textangle ( 90 );
 | 
						|
	//plotter.alabel    ( 'c' , 'c' , "disk accesses" );
 | 
						|
 | 
						|
	// find time ranges
 | 
						|
	int64_t t2 = 0;
 | 
						|
	for ( int32_t i = 0 ; i < MAX_POINTS ; i++ ) {
 | 
						|
		// skip empties
 | 
						|
		if ( m_pts[i].m_startTime == 0 ) continue;
 | 
						|
		// set min/max
 | 
						|
		if ( m_pts[i].m_endTime   > t2 ) t2 = m_pts[i].m_endTime;
 | 
						|
	}
 | 
						|
	// now compute the start time for the graph
 | 
						|
	int64_t t1 = 0x7fffffffffffffffLL;
 | 
						|
	// now recompute t1
 | 
						|
	for ( int32_t i = 0 ; i < MAX_POINTS ; i++ ) {
 | 
						|
		// skip empties
 | 
						|
		if ( m_pts[i].m_startTime == 0 ) continue;
 | 
						|
		// can't be behind more than 1 second
 | 
						|
		if ( m_pts[i].m_startTime   < t2 - DT ) continue;
 | 
						|
		// otherwise, it's a candidate for the first time
 | 
						|
		if ( m_pts[i].m_startTime < t1 ) t1 = m_pts[i].m_startTime;
 | 
						|
	}
 | 
						|
	// what's the delta t? just make it 1000 ms
 | 
						|
	//int64_t dt = 1000; // t2 - t1;
 | 
						|
 | 
						|
	// get time range scaling info
 | 
						|
	//int64_t t1 = m_minWindowStartTime;
 | 
						|
	//int64_t t2 = gettimeofdayInMilliseconds();
 | 
						|
	//if ( startTime > 0 && t1 < startTime ) t1 = startTime;
 | 
						|
	//if ( endTime   > 0 && t2 > endTime   ) t2 = endTime;
 | 
						|
 | 
						|
	// 10 x-axis tick marks
 | 
						|
	for ( int x = DX/10 ; x < DX ; x += DX/10 ) {
 | 
						|
		// tick mark
 | 
						|
		plotter.line ( x , -20 , x , 20 );
 | 
						|
		// generate label
 | 
						|
		char buf [ 32 ];
 | 
						|
		sprintf ( buf , "%" INT32 "" , 
 | 
						|
			  (int32_t)(DT * (int64_t)x / (int64_t)DX) );
 | 
						|
		// move cursor
 | 
						|
		plotter.move ( x , -by / 2 - 9 );
 | 
						|
		// plot label
 | 
						|
		plotter.alabel     ( 'c' , 'c' , buf );
 | 
						|
	}
 | 
						|
 | 
						|
	// . each line consists of several points
 | 
						|
	// . we need to know each point for adding otherlines
 | 
						|
	// . is about [400/6][1024] = 70k
 | 
						|
	// . each line can contain multiple data points
 | 
						|
	// . each data point is expressed as a horizontal line segment
 | 
						|
	void *lrgBuf;
 | 
						|
	int32_t lrgSize = 0;
 | 
						|
	lrgSize += MAX_LINES * MAX_POINTS * sizeof(StatPoint *);
 | 
						|
	lrgSize += MAX_LINES * sizeof(int32_t);
 | 
						|
	lrgBuf = (char *) mmalloc(lrgSize, "Stats.cpp"); 
 | 
						|
	if (! lrgBuf) {
 | 
						|
	    log("could not allocate memory for local buffer in Stats.cpp"
 | 
						|
		"%" INT32 " bytes needed", lrgSize);
 | 
						|
	    return;
 | 
						|
	}
 | 
						|
	char *lrgPtr = (char *)lrgBuf;
 | 
						|
	StatPoint **points = (StatPoint **)lrgPtr;   
 | 
						|
	lrgPtr += MAX_LINES * MAX_POINTS * sizeof(StatPoint *);
 | 
						|
	int32_t *numPoints = (int32_t *)lrgPtr;
 | 
						|
	lrgPtr += MAX_LINES * sizeof(int32_t);
 | 
						|
	memset ( (char *)numPoints , 0 , MAX_LINES * sizeof(int32_t) );
 | 
						|
 | 
						|
	// store the data points into "lines"
 | 
						|
	int32_t count = MAX_POINTS;
 | 
						|
	for ( int32_t i = m_next ; count >= 0 ; i++ , count-- ) {
 | 
						|
		// wrap around the array
 | 
						|
		if ( i >= MAX_POINTS ) i = 0;
 | 
						|
		// skip point if empty
 | 
						|
		if ( m_pts[i].m_startTime == 0 ) continue;
 | 
						|
		// skip if too early
 | 
						|
		if ( m_pts[i].m_endTime < t1 ) continue;
 | 
						|
		// . find the lowest line the will hold us
 | 
						|
		// . this adds point to points[x][n] where x is determined
 | 
						|
		addPoint ( points , numPoints , &m_pts[i] );
 | 
						|
	}
 | 
						|
 | 
						|
	int y1 = 21;
 | 
						|
	// plot the points (lines) in each line
 | 
						|
	for ( int32_t i = 0 ; i < MAX_LINES    ; i++ ) {
 | 
						|
		// increase vert
 | 
						|
		y1 += MAX_WIDTH + 1;
 | 
						|
		// wrap back down if necessary
 | 
						|
		if ( y1 >= DY ) y1 = 21;
 | 
						|
		// plt all points in this row
 | 
						|
	for ( int32_t j = 0 ; j < numPoints[i] ; j++ ) {
 | 
						|
		// get the point
 | 
						|
		StatPoint *p =  points[MAX_POINTS * i + j];
 | 
						|
		// transform time to x coordinates
 | 
						|
		int x1 = (p->m_startTime - t1) * (int64_t)DX / DT;
 | 
						|
		int x2 = (p->m_endTime   - t1) * (int64_t)DX / DT;
 | 
						|
		// if x2 is negative, skip it
 | 
						|
		if ( x2 < 0 ) continue;
 | 
						|
		// if x1 is negative, boost it to -2
 | 
						|
		if ( x1 < 0 ) x1 = -2;
 | 
						|
		// . line thickness is function of read/write size
 | 
						|
		// . take logs
 | 
						|
		int w = (int)log(((double)p->m_numBytes)/8192.0) + 3;
 | 
						|
		//log("log of %" INT32 " is %i",m_pts[i].m_numBytes,w);
 | 
						|
		if ( w < 3         ) w = 3;
 | 
						|
		if ( w > MAX_WIDTH ) w = MAX_WIDTH;
 | 
						|
		plotter.linewidth ( w );       
 | 
						|
		// use the color specified from addStat_r() for this line/pt
 | 
						|
		plotter.pencolor ( ((p->m_color >> 16) & 0xff) << 8 ,
 | 
						|
				   ((p->m_color >>  8) & 0xff) << 8 ,
 | 
						|
				   ((p->m_color >>  0) & 0xff) << 8 );
 | 
						|
		// ensure at least 3 units wide for visibility
 | 
						|
		if ( x2 < x1 + 3 ) x2 = x1 + 3;
 | 
						|
		// . flip the y so we don't have to scroll the browser down
 | 
						|
		// . DY does not include the axis and tick marks
 | 
						|
		int32_t fy1 = DY - y1 + 20 ;
 | 
						|
		// plot it
 | 
						|
		plotter.line ( x1 , fy1 , x2 , fy1 );
 | 
						|
		// debug msg
 | 
						|
		//log("line (%i,%i, %i,%i) ", x1 , vert , x2 , vert );
 | 
						|
		//log("bytes = %" INT32 " width = %" INT32 " ", m_pts[i].m_numBytes,w);
 | 
						|
		//log("st=%i, end=%i color=%" XINT32 " " ,
 | 
						|
		//      (int)m_pts[i].m_startTime , 
 | 
						|
		//      (int)m_pts[i].m_endTime   , 
 | 
						|
		//      m_pts[i].m_color );
 | 
						|
	}
 | 
						|
	}
 | 
						|
 | 
						|
	// all done
 | 
						|
	if ( plotter.closepl () < 0 ) 
 | 
						|
		log("admin: Could not close performance graph object.");
 | 
						|
 | 
						|
	// plotter uses malloc, so we must get the lock from Mem.cpp
 | 
						|
	//m_gotLock = false;
 | 
						|
	//mutexUnlock();
 | 
						|
 | 
						|
	// close the file
 | 
						|
	fclose ( fd );
 | 
						|
	mfree(lrgBuf, lrgSize, "Stats.cpp");
 | 
						|
#endif
 | 
						|
}
 | 
						|
*/
 | 
						|
 | 
						|
void Stats::addPoint (StatPoint **points    , 
 | 
						|
		      int32_t       *numPoints ,
 | 
						|
		      StatPoint  *p         ) {
 | 
						|
	// go down each line of points
 | 
						|
	for ( int32_t i = 0 ; i < MAX_LINES ; i++ ) {
 | 
						|
		// is there room for us in this line?
 | 
						|
		int32_t n = numPoints[i];
 | 
						|
		// if line is full, skip it
 | 
						|
		if ( n >= MAX_POINTS ) continue;
 | 
						|
		int32_t j;
 | 
						|
		// make a boundary around point there already
 | 
						|
		int64_t a = p->m_startTime;
 | 
						|
		int64_t b = p->m_endTime;
 | 
						|
		// . for a space to appear we need to be separated
 | 
						|
		//   by this many milliseconds
 | 
						|
		// . this is milliseconds per pixel
 | 
						|
		// . right now it's about 5
 | 
						|
		int32_t border = DT / DX ;
 | 
						|
		if ( border <= 0 ) border = 1;
 | 
						|
		a -= 4*border;
 | 
						|
		b += 4*border;
 | 
						|
		// debug
 | 
						|
		//log("a=%" INT64 " b=%" INT64 " d=%" INT32 "",a,b,4*border);
 | 
						|
		for ( j = 0 ; j < n ; j++ ) {
 | 
						|
			// get that point
 | 
						|
			StatPoint *pp = points[MAX_POINTS * i + j];
 | 
						|
			// . do we intersect this point (horizontal line)?
 | 
						|
			// . if so, break out
 | 
						|
			if ( pp->m_startTime >= a && pp->m_startTime <= b )
 | 
						|
				break;
 | 
						|
			if ( pp->m_endTime   >= a && pp->m_endTime   <= b )
 | 
						|
				break;
 | 
						|
		}
 | 
						|
		// if j is < n then there's no room
 | 
						|
		if ( j < n ) continue;
 | 
						|
		// otherwise, add our point
 | 
						|
		points[MAX_POINTS * i + n] = p;
 | 
						|
		numPoints[i]++;
 | 
						|
		return;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void Stats::calcQueryStats() {
 | 
						|
	int64_t now = gettimeofdayInMilliseconds();
 | 
						|
	m_upTime = now - m_startTime;
 | 
						|
	m_avgQueryTime  = (float)m_queryTimes /
 | 
						|
		((float)m_numQueries * 1000.0);
 | 
						|
	m_successRate = (float)m_numSuccess / 
 | 
						|
		(float)(m_numSuccess + m_numFails);
 | 
						|
	//(number of queries) / seconds that it took to get this many queries
 | 
						|
	m_avgQueriesPerSec = ((float)m_numQueries * 1000.0) / 
 | 
						|
		(float)(now - m_lastQueryLogTime);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void Stats::logAvgQueryTime(int64_t startTime) {
 | 
						|
	int64_t now = gettimeofdayInMilliseconds();
 | 
						|
	int64_t took = now - startTime;
 | 
						|
	static int32_t s_lastSendTime = 0;
 | 
						|
	// if just one query took an insanely int32_t time,
 | 
						|
	// do not sound the alarm. this is in seconds,
 | 
						|
	// so multiply by 1000.
 | 
						|
	//int64_t maxTook = 
 | 
						|
	//	(int64_t)(g_conf.m_maxQueryTime*1000.0) ;
 | 
						|
	//if ( took > maxTook ) took = maxTook;
 | 
						|
	m_queryTimes += took;
 | 
						|
	m_numQueries++;
 | 
						|
 | 
						|
	if ( m_numQueries > g_conf.m_numQueryTimes )
 | 
						|
		goto reset;
 | 
						|
 | 
						|
	if (m_numQueries != g_conf.m_numQueryTimes) return;
 | 
						|
	// otherwise, store this info
 | 
						|
	m_avgQueryTime  = (float)m_queryTimes /
 | 
						|
		((float)m_numQueries * 1000.0);
 | 
						|
	m_successRate = (float)m_numSuccess / 
 | 
						|
		(float)(m_numSuccess + m_numFails);
 | 
						|
	//(number of queries) / seconds that it took to get this many queries
 | 
						|
	m_avgQueriesPerSec = ((float)m_numQueries * 1000.0) / 
 | 
						|
		(float)(now - m_lastQueryLogTime);
 | 
						|
	m_lastQueryLogTime = now;
 | 
						|
 | 
						|
	if(m_avgQueryTime > g_conf.m_avgQueryTimeThreshold ||
 | 
						|
	   m_successRate  < g_conf.m_querySuccessThreshold) {
 | 
						|
		char msgbuf[1024];
 | 
						|
		Host *h = g_hostdb.getHost ( 0 );
 | 
						|
		snprintf(msgbuf, 1024,
 | 
						|
			 "Average latency: %f sec. "
 | 
						|
			 "success rate: %f.  "
 | 
						|
			 "queries/sec: %f.  "
 | 
						|
			 "host: %s.",
 | 
						|
			 m_avgQueryTime, m_successRate, m_avgQueriesPerSec,
 | 
						|
			 iptoa(h->m_ip));
 | 
						|
		log(LOG_WARN, "query: %s",msgbuf);
 | 
						|
		// prevent machinegunning text msgs
 | 
						|
		int32_t now = getTimeLocal();
 | 
						|
		if ( now - s_lastSendTime > 300 ) {
 | 
						|
			s_lastSendTime = now;
 | 
						|
			g_pingServer.sendEmail(NULL, msgbuf);
 | 
						|
		}
 | 
						|
	}
 | 
						|
	else {
 | 
						|
		log(LOG_INFO, "query: Average latency is %f seconds, "
 | 
						|
		    "succeeding at a rate of %f, serving %f queries/sec.",
 | 
						|
		    m_avgQueryTime, m_successRate, m_avgQueriesPerSec);
 | 
						|
	}
 | 
						|
 reset:
 | 
						|
	m_totalNumQueries += m_numSuccess + m_numFails;
 | 
						|
	m_totalNumSuccess += m_numSuccess;
 | 
						|
	m_totalNumFails   += m_numFails;
 | 
						|
	
 | 
						|
	m_numQueries = 0;
 | 
						|
	m_queryTimes = 0;
 | 
						|
	m_numSuccess = 0;
 | 
						|
	m_numFails = 0;
 | 
						|
}
 | 
						|
 | 
						|
void Stats::addSpiderPoint ( int32_t errCode, bool isNew ) {
 | 
						|
	// keep track of last 1000 urls spidered
 | 
						|
	int32_t i = m_spiderSample % 1000;
 | 
						|
	if ( m_errCodes[i] ) m_spiderErrors--;
 | 
						|
	if ( m_isSampleNew[i] ) m_spiderNew--;
 | 
						|
	if ( m_errCodes[i] && m_isSampleNew[i] ) m_spiderErrorsNew--;
 | 
						|
	m_errCodes[i] = errCode;
 | 
						|
	m_isSampleNew[i] = (char)isNew;
 | 
						|
	if ( m_errCodes[i] ) m_spiderErrors++;
 | 
						|
	if ( m_isSampleNew[i] ) m_spiderNew++;
 | 
						|
	if ( m_errCodes[i] && m_isSampleNew[i] ) m_spiderErrorsNew++;
 | 
						|
	m_spiderSample++;
 | 
						|
 | 
						|
	// keep track of total spiders
 | 
						|
	if ( isNew ) {
 | 
						|
		if ( errCode ) m_totalSpiderErrorsNew++;
 | 
						|
		else           m_totalSpiderSuccessNew++;
 | 
						|
		m_allErrorsNew[errCode]++;
 | 
						|
	}
 | 
						|
	else {
 | 
						|
		if ( errCode ) m_totalSpiderErrorsOld++;
 | 
						|
		else           m_totalSpiderSuccessOld++;
 | 
						|
		m_allErrorsOld[errCode]++;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// draw a HORIZONTAL line in html
 | 
						|
void drawLine2 ( SafeBuf &sb ,
 | 
						|
		 int32_t x1 , 
 | 
						|
		 int32_t x2 ,
 | 
						|
		 int32_t fy1 , 
 | 
						|
		 int32_t color ,
 | 
						|
		 int32_t width ) {
 | 
						|
 | 
						|
	sb.safePrintf("<div style=\"position:absolute;"
 | 
						|
		      "left:%" INT32 ";"
 | 
						|
		      "top:%" INT32 ";"
 | 
						|
		      "background-color:#%06" XINT32 ";"
 | 
						|
		      "z-index:5;"
 | 
						|
		      "min-height:%" INT32 "px;"
 | 
						|
		      "min-width:%" INT32 "px;\"></div>\n"
 | 
						|
		      , x1
 | 
						|
		      , (fy1 - width/2) - 20 //- 300
 | 
						|
		      , color
 | 
						|
		      , width
 | 
						|
		      , x2 - x1
 | 
						|
		      );
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
//
 | 
						|
// new code for drawing graph in html with absolute divs instead
 | 
						|
// of using GIF plotter library which had issues
 | 
						|
//
 | 
						|
void Stats::printGraphInHtml ( SafeBuf &sb ) {
 | 
						|
 | 
						|
	// gif size
 | 
						|
	char tmp[64];
 | 
						|
	sprintf ( tmp , "%" INT32 "x%" INT32 "", (int32_t)DX+40 , (int32_t)DY+40 ); // "1040x440"
 | 
						|
 | 
						|
	// 20 pixel borders
 | 
						|
	//int bx = 10;
 | 
						|
	//int by = 30;
 | 
						|
	// define the space with boundaries 100 unit wide boundaries
 | 
						|
	//plotter.space ( -bx , -by , DX + bx , DY + by );
 | 
						|
	// draw the x-axis
 | 
						|
	//plotter.line ( 0 , 0 , DX , 0  );
 | 
						|
	// draw the y-axis
 | 
						|
	//plotter.line ( 0 , 0 ,  0 , DY );
 | 
						|
 | 
						|
	// find time ranges
 | 
						|
	int64_t t2 = 0;
 | 
						|
	for ( int32_t i = 0 ; i < MAX_POINTS ; i++ ) {
 | 
						|
		// skip empties
 | 
						|
		if ( m_pts[i].m_startTime == 0 ) continue;
 | 
						|
		// set min/max
 | 
						|
		if ( m_pts[i].m_endTime   > t2 ) t2 = m_pts[i].m_endTime;
 | 
						|
	}
 | 
						|
	// now compute the start time for the graph
 | 
						|
	int64_t t1 = 0x7fffffffffffffffLL;
 | 
						|
	// now recompute t1
 | 
						|
	for ( int32_t i = 0 ; i < MAX_POINTS ; i++ ) {
 | 
						|
		// skip empties
 | 
						|
		if ( m_pts[i].m_startTime == 0 ) continue;
 | 
						|
		// can't be behind more than 1 second
 | 
						|
		if ( m_pts[i].m_startTime   < t2 - DT ) continue;
 | 
						|
		// otherwise, it's a candidate for the first time
 | 
						|
		if ( m_pts[i].m_startTime < t1 ) t1 = m_pts[i].m_startTime;
 | 
						|
	}
 | 
						|
 | 
						|
	//
 | 
						|
	// main graphing window
 | 
						|
	//
 | 
						|
	sb.safePrintf("<div style=\"position:relative;"
 | 
						|
		      "background-color:#c0c0c0;"
 | 
						|
 | 
						|
		      // match style of tables
 | 
						|
		      "border-radius:10px;"
 | 
						|
		      "border:#6060f0 2px solid;"
 | 
						|
		      
 | 
						|
		      //"overflow-y:hidden;"
 | 
						|
		      "overflow-x:hidden;"
 | 
						|
		      //"z-index:-10;"
 | 
						|
		      // the tick marks we print below are based on it
 | 
						|
		      // being a window of the last 20 seconds... and using
 | 
						|
		      // DX pixels
 | 
						|
		      "min-width:%" INT32 "px;"
 | 
						|
		      "min-height:%" INT32 "px;"
 | 
						|
		      //"width:100%%;"
 | 
						|
		      //"min-height:600px;"
 | 
						|
		      //"margin-top:10px;"
 | 
						|
		      "margin-bottom:10px;"
 | 
						|
		      //"margin-right:10px;"
 | 
						|
		      //"margin-left:10px;"
 | 
						|
		      "\">"
 | 
						|
		      ,(int32_t)DX
 | 
						|
		      ,(int32_t)DY +20); // add 10 more for "2s" labels etc.
 | 
						|
 | 
						|
	// 10 x-axis tick marks
 | 
						|
	for ( int x = DX/20 ; x <= DX ; x += DX/20 ) {
 | 
						|
		// tick mark
 | 
						|
		//plotter.line ( x , -20 , x , 20 );
 | 
						|
		sb.safePrintf("<div style=\"position:absolute;"
 | 
						|
			      "left:%" INT32 ";"
 | 
						|
			      "bottom:0;"
 | 
						|
			      "background-color:#000000;"
 | 
						|
			      "z-index:110;"
 | 
						|
			      "min-height:20px;"
 | 
						|
			      "min-width:3px;\"></div>\n"
 | 
						|
			      , (int32_t)x-1
 | 
						|
			      );
 | 
						|
		// generate label
 | 
						|
		//char buf [ 32 ];
 | 
						|
		//sprintf ( buf , "%" INT32 "" , 
 | 
						|
		//	  (int32_t)(DT * (int64_t)x / (int64_t)DX) );
 | 
						|
		// LABEL
 | 
						|
		sb.safePrintf("<div style=\"position:absolute;"
 | 
						|
			      "left:%" INT32 ";"
 | 
						|
			      "bottom:20;"
 | 
						|
			      //"background-color:#000000;"
 | 
						|
			      "z-index:110;"
 | 
						|
			      "min-height:20px;"
 | 
						|
			      "min-width:3px;\">%.01fs</div>\n"
 | 
						|
			      , (int32_t)x-10
 | 
						|
			      // the label:
 | 
						|
			      ,(float)(DT* (int64_t)x / (int64_t)DX)/1000.0
 | 
						|
			      );
 | 
						|
 | 
						|
		// move cursor
 | 
						|
		//plotter.move ( x , -by / 2 - 9 );
 | 
						|
		// plot label
 | 
						|
		//plotter.alabel     ( 'c' , 'c' , buf );
 | 
						|
	}
 | 
						|
 | 
						|
	// . each line consists of several points
 | 
						|
	// . we need to know each point for adding otherlines
 | 
						|
	// . is about [400/6][1024] = 70k
 | 
						|
	// . each line can contain multiple data points
 | 
						|
	// . each data point is expressed as a horizontal line segment
 | 
						|
	void *lrgBuf;
 | 
						|
	int32_t lrgSize = 0;
 | 
						|
	lrgSize += MAX_LINES * MAX_POINTS * sizeof(StatPoint *);
 | 
						|
	lrgSize += MAX_LINES * sizeof(int32_t);
 | 
						|
	lrgBuf = (char *) mmalloc(lrgSize, "Stats.cpp"); 
 | 
						|
	if (! lrgBuf) {
 | 
						|
	    log("could not allocate memory for local buffer in Stats.cpp"
 | 
						|
		"%" INT32 " bytes needed", lrgSize);
 | 
						|
	    return;
 | 
						|
	}
 | 
						|
	char *lrgPtr = (char *)lrgBuf;
 | 
						|
	StatPoint **points = (StatPoint **)lrgPtr;   
 | 
						|
	lrgPtr += MAX_LINES * MAX_POINTS * sizeof(StatPoint *);
 | 
						|
	int32_t *numPoints = (int32_t *)lrgPtr;
 | 
						|
	lrgPtr += MAX_LINES * sizeof(int32_t);
 | 
						|
	memset ( (char *)numPoints , 0 , MAX_LINES * sizeof(int32_t) );
 | 
						|
 | 
						|
	// store the data points into "lines"
 | 
						|
	int32_t count = MAX_POINTS;
 | 
						|
	for ( int32_t i = m_next ; count >= 0 ; i++ , count-- ) {
 | 
						|
		// wrap around the array
 | 
						|
		if ( i >= MAX_POINTS ) i = 0;
 | 
						|
		// skip point if empty
 | 
						|
		if ( m_pts[i].m_startTime == 0 ) continue;
 | 
						|
		// skip if too early
 | 
						|
		if ( m_pts[i].m_endTime < t1 ) continue;
 | 
						|
		// . find the lowest line the will hold us
 | 
						|
		// . this adds point to points[x][n] where x is determined
 | 
						|
		addPoint ( points , numPoints , &m_pts[i] );
 | 
						|
	}
 | 
						|
 | 
						|
	int y1 = 21;
 | 
						|
	// plot the points (lines) in each line
 | 
						|
	for ( int32_t i = 0 ; i < MAX_LINES    ; i++ ) {
 | 
						|
		// increase vert
 | 
						|
		y1 += MAX_WIDTH + 1;
 | 
						|
		// wrap back down if necessary
 | 
						|
		if ( y1 >= DY ) y1 = 21;
 | 
						|
		// plt all points in this row
 | 
						|
	for ( int32_t j = 0 ; j < numPoints[i] ; j++ ) {
 | 
						|
		// get the point
 | 
						|
		StatPoint *p =  points[MAX_POINTS * i + j];
 | 
						|
		// transform time to x coordinates
 | 
						|
		int x1 = (p->m_startTime - t1) * (int64_t)DX / DT;
 | 
						|
		int x2 = (p->m_endTime   - t1) * (int64_t)DX / DT;
 | 
						|
		// if x2 is negative, skip it
 | 
						|
		if ( x2 < 0 ) continue;
 | 
						|
		// if x1 is negative, boost it to -2
 | 
						|
		if ( x1 < 0 ) x1 = -2;
 | 
						|
		// . line thickness is function of read/write size
 | 
						|
		// . take logs
 | 
						|
		int w = (int)log(((double)p->m_numBytes)/8192.0) + 3;
 | 
						|
		//log("log of %" INT32 " is %i",m_pts[i].m_numBytes,w);
 | 
						|
		if ( w < 3         ) w = 3;
 | 
						|
		if ( w > MAX_WIDTH ) w = MAX_WIDTH;
 | 
						|
		//plotter.linewidth ( w );       
 | 
						|
		// use the color specified from addStat_r() for this line/pt
 | 
						|
		//plotter.pencolor ( ((p->m_color >> 16) & 0xff) << 8 ,
 | 
						|
		//		   ((p->m_color >>  8) & 0xff) << 8 ,
 | 
						|
		//		   ((p->m_color >>  0) & 0xff) << 8 );
 | 
						|
		// ensure at least 3 units wide for visibility
 | 
						|
		if ( x2 < x1 + 3 ) x2 = x1 + 3;
 | 
						|
		// . flip the y so we don't have to scroll the browser down
 | 
						|
		// . DY does not include the axis and tick marks
 | 
						|
		int32_t fy1 = DY - y1 + 20 ;
 | 
						|
		// plot it
 | 
						|
		//plotter.line ( x1 , fy1 , x2 , fy1 );
 | 
						|
		drawLine2 ( sb , x1 , x2 , fy1 , p->m_color , w );
 | 
						|
		// debug msg
 | 
						|
		//log("line (%i,%i, %i,%i) ", x1 , vert , x2 , vert );
 | 
						|
		//log("bytes = %" INT32 " width = %" INT32 " ", m_pts[i].m_numBytes,w);
 | 
						|
		//log("st=%i, end=%i color=%" XINT32 " " ,
 | 
						|
		//      (int)m_pts[i].m_startTime , 
 | 
						|
		//      (int)m_pts[i].m_endTime   , 
 | 
						|
		//      m_pts[i].m_color );
 | 
						|
	}
 | 
						|
	}
 | 
						|
 | 
						|
	sb.safePrintf("</div>\n");
 | 
						|
 | 
						|
	mfree(lrgBuf, lrgSize, "Stats.cpp");
 | 
						|
}
 |