Click here to Skip to main content
15,894,907 members
Articles / Desktop Programming / MFC

.NET Dynamic Software Load Balancing

Rate me:
Please Sign up or sign in to vote.
4.96/5 (111 votes)
9 Dec 200271 min read 511.6K   4.5K   242  
A Draft Implementation of an Idea for .NET Dynamic Software Load Balancing
//////////////////////////////////////////////////////////////////////////////
// .NET Dynamic Software Load Balancing
// A Draft Implementation of an Idea for .NET Dynamic Software Load Balancing
// (c) 2002, Stoyan Damov (stoyan_damov@hotmail.com)
// The software comes �AS IS�, with all faults and no warranties.
//////////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "ReportingWorker.h"

using namespace System::Text;
using namespace System::Collections;

namespace SoftwareLoadBalancing
{

ReportingWorker::ReportingWorker (
	LoadReportingServer __gc* server,
	WorkerDoneEventHandler __gc* workerDoneCallback,
	IPAddress __gc* ipAddress,
	int port,
	int reportInterval,
	ArrayList __gc* performanceCounters) :
		Tracer (S"ReportingWorker")
{
	Trace (S"Initializing...");

	DEBUG_ASSERT (0 != server);
	if (0 == server)
		throw (new ArgumentNullException ("server"));

	DEBUG_ASSERT (0 != ipAddress);
	if (0 == ipAddress)
		throw (new ArgumentNullException ("ipAddress"));

	DEBUG_ASSERT (0 != workerDoneCallback);
	if (0 == workerDoneCallback)
		throw (new ArgumentNullException ("workerDoneCallback"));

	DEBUG_ASSERT (0 != performanceCounters);
	if (0 == performanceCounters)
		throw (new ArgumentNullException ("performanceCounters"));

	this->server = server;
	this->workerDoneCallback = workerDoneCallback;
	this->machineName = Environment::MachineName;
	this->ipAddress = ipAddress;
	this->port = port;
	this->reportInterval = reportInterval;
	this->counters = performanceCounters;
	
	Trace (S"Initialization done.");
}

void ReportingWorker::Run ()
{
	Trace (S"Configuring...");

	int counterCount = counters->Count;
	DEBUG_ASSERT (counterCount > 0);
	if (counterCount <= 0)
	{
		workerDoneCallback->Invoke (false);
		return;
	}
	
	Trace (S"Configuration done.");
	
	Trace (S"Starting performance counters monitoring...");
	// start the counters monitoring
	//
	try
	{
		for (int i=0; i<counterCount; i++)
		{
			CounterInfo __gc* counterInfo = 
				static_cast<CounterInfo __gc*> (counters->get_Item (i));
			counterInfo->StartCollecting ();
		}
	}
	catch (Exception __gc* e)
	{
		TRACE_EXCEPTION_AND_RETHROW_IF_NEEDED (e);
		// inform the main thread that we failed
		//
		workerDoneCallback->Invoke (false);

		// stop running the thread
		//
		return;
	}
	Trace (S"Performance counters monitoring started.");

	// if we got here, everything went OK
	//
	workerDoneCallback->Invoke (true);

	Trace (S"Entering thread loop...");
	try
	{
		// here starts the thread loop
		//
		Socket __gc* socket = 0;
		SOCKET_CREATE (socket);
		SOCKET_ADD_MEMBERSHIP (socket, ipAddress);
		
		IPEndPoint __gc* remoteEndPoint = new IPEndPoint (ipAddress, port);				
		int timeLeftToReportAgain = reportInterval;
		while (server->Status != ServerStatus::Stopping)
		{
			if (timeLeftToReportAgain <= 0)
			{
				// get the machine load; as of now, the machine load is
				// considered to be the sum of all weighted averages
				//
				double load = 0.00;
				for (int i=0; i<counterCount; i++)
				{
					CounterInfo __gc* counterInfo = 
						static_cast<CounterInfo __gc*> (counters->get_Item (i));
					load += counterInfo->WeightedAverage;
				}
				unsigned long roundedLoad = (unsigned long) load;
				String __gc* message = String::Format (
					S"MACH {0} LOAD {1}",
					machineName,
					__box (roundedLoad));

				// try to report the machine load
				//
				try
				{
					byte buffer __gc[] = Encoding::UTF8->GetBytes (message);
					SOCKET_SEND (socket, remoteEndPoint, buffer);
					MiniTrace (S".");
				}
				catch (Exception __gc* e)
				{
					TRACE_EXCEPTION_AND_RETHROW_IF_NEEDED (e);
					MiniTrace (S"!");
				}
				
				// reset the time left to report
				//
				timeLeftToReportAgain = reportInterval;
				continue;
			}
			// sleep for a while
			//
			Thread::Sleep (WorkerThreadSleepTime);
			// update the time left to report
			//
			timeLeftToReportAgain -= WorkerThreadSleepTime;
		}

		// cleanup
		//		
		SOCKET_DROP_MEMBERSHIP (socket, ipAddress);
		SOCKET_CLOSE (socket)
	}
	catch (ThreadAbortException __gc*)
	{
		Trace (S"Thread aborted. Giving up.");
		// just let the cleanup code below execute and exit
		//
		Thread::ResetAbort ();
	}
	Trace (S"Exited thread loop.");

	Trace (S"Stopping performance counters monitoring...");
	// stop the counters
	//
	try
	{
		for (int i=0; i<counterCount; i++)
		{
			CounterInfo __gc* counterInfo = 
				static_cast<CounterInfo __gc*> (counters->get_Item (i));
			counterInfo->StopCollecting ();
		}
	}
	catch (Exception __gc* e)
	{
		TRACE_EXCEPTION_AND_RETHROW_IF_NEEDED (e);
	}
	Trace (S"Performance counters monitoring stopped.");
}

} // namespace

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
Bulgaria Bulgaria
I'm crazy about programming, bleeding-edge technologies and my wife, Irina. Thinking seriously to start living in Centurian time.

The image shows me, happy :P

My blog

Comments and Discussions