Blog

Run Loop

So I have created the foundation for the next work. I have managed to get all the run parameters​ from an XML file and loaded them into variables in main of the MCP C++ program. I had to do a little restructuring of the code as the includes for thread and time needed to be moved to the shared include as the methods in the classes used some of the same libraries.

So the main looks like this, it will not likely get much larger than this (as always the code is better spaced in the editor in AWS cloud9):

#include "mcp.cpp"

int main()
{
        
	// Print a header of execution out
	auto result = std::time(nullptr);	
	std::cout << "Start: Master Control Program " << std::endl;
	std::cout << "Local Time: " <<
	    std::asctime(std::localtime(&result)) << std::endl;
	    
    // Get running values
    std::string versionnumber, storedirectory, sharedirectory, UUID[10];
    
    MCPParms ourparms("MCP.xml"); // parms for program
    try {
        
        ourparms.load();
    }
    
    catch (std::exception const&  ex) {
        
       std::cout << ex.what() << std::endl;
       return (1);
    }
	
	ourparms.version(versionnumber);
	
	// Write out version number
	std::cout << "File version: " << versionnumber << std::endl;
	
	ourparms.UUID(UUID);
	
	ourparms.store(storedirectory);
	
	ourparms.share(sharedirectory);
	
	int client = ourparms.client();
	
	std::cout << "Client " << client;
	if (client == 0) {
	    std::cout << " Primary!";
	}
	std::cout << std::endl;
	std::cout << "Store: " << storedirectory << std::endl;
	std::cout << "Share: " << sharedirectory << std::endl;
	
	// Start run loop for MCP
	MCPRun runit(1000, storedirectory); // set wait time
	
	runit.run();
	
	// Close down task
	
	std::this_thread::sleep_for(std::chrono::milliseconds(1000));
	
	// Shutdown
	result = std::time(nullptr);
    std::cout << "Exit: Master Control Program " << std::endl;
	std::cout << "Local Time: " <<
	    std::asctime(std::localtime(&result)) << std::endl;
	    
    // Leave politely
    return 0;

}

 
The run routine is working and now starts up a loop with 1000 millisecond wait and checks if the file in the store directory named run.xml is present, well-formed​, and has a ‘run’ value of ‘Yes’. So the MCP begins to act like a master control program now as it loops until requested to a ​shutdown of fail-out if it cannot find the control file that allows it to run.

The run code:

MCPRun::MCPRun(int mywaittime, const std::string &mystore)
{
   runfile = mystore + "/run.xml"; // put hard coding inside
   storedirectory = mystore;
   waittime = mywaittime;
   shutdown = "Start";
   
   return;

}

void MCPRun::run()
/*
    This is the main control loop. It runs until the check becomes false. There
    must be a wait long enough to not cause this to take over the system, at
    least a second.
    
*/

{

   do {
   
        std::this_thread::sleep_for(std::chrono::milliseconds(waittime));
   
   } while (check());
   
   std::cout << "Ending Condition: " << shutdown << std::endl;
   
   return;

}

bool MCPRun::check()
/*
    The check opens the run.xml in the store and stops when the run value is not
    "Yes" or the file is not there or malformed.
*/

{
    std::string therun;
    therun = "No";
    try {
        
        pt::read_xml(runfile, tree); // exceptions must be handled!
        therun = tree.get("run", "No"); // no throw if not there
    }
    
    catch (std::exception const&  ex) {
        
       therun = "Fail";
       shutdown = "Fail";

    }
   //std::cout << "Check: " << therun << std::endl;
   
   return (therun == "Yes");

}

Well all of the work now begins to pay. Next, and I am having issues with this step, is to scan the share directory for files to process.

More coding

So I have more C++ to relearn. I had to remember how to pass by reference and update same. I reworked the code to move all the hard coding to the routine and thus hid all of it.

Here is a bit of the main now:

int main()
{
        
	// Print a header of execution out
	auto result = std::time(nullptr);	
	std::cout << "Start: Master Control Program " << std::endl;
	std::cout << "Local Time: " <<
	    std::asctime(std::localtime(&result)) << std::endl;
	    
    // Get running values
    std::string versionnumber, storedirectory, sharedirectory, UUID[10];
    
    MCPParms ourparms("MCP.xml"); // parms for program
    try {
        
        ourparms.load();
    }
    
    catch (std::exception const&  ex) {
        
       std::cout << ex.what() << std::endl;
       return (1);
    }
	
	ourparms.version(versionnumber);
	
	// Write out version number
	std::cout << "File version: " << versionnumber << std::endl;
	
	ourparms.UUID(UUID);
	// write out UUID of starting value
	std::cout << "UUID " << UUID[0] << std::endl;
	
	ourparms.store(storedirectory);
	
	ourparms.share(sharedirectory);
	
	int client = ourparms.client();
	
	std::cout << "Client " << client;
	if (client == 0) {
	    std::cout << " Primary!";
	}
	std::cout << std::endl;
	std::cout << "Store: " << storedirectory << std::endl;
	std::cout << "Share: " << sharedirectory << std::endl;
	
	std::this_thread::sleep_for(std::chrono::milliseconds(1000));
	
	// Shutdown
	result = std::time(nullptr);
    std::cout << "Exit: Master Control Program " << std::endl;
	std::cout << "Local Time: " <<
	    std::asctime(std::localtime(&result)) << std::endl;
	    
    // Leave politely
    return 0;

}

I have left the open of the file to be a try/except as I think it would hard to handle it in the constructor. I have moved the getting of values to methods.

That code looks like this (please notice the one bit of crazy C++ code that is obscure):

void MCPParms::version(std::string &myversion)
{
    
    myversion = this->get("mcp.version");
    
    return;
}

void MCPParms::UUID(std::string myUUID[10])
{
    
    myUUID[0] = this->get("UUID.0");
    myUUID[1] = this->get("UUID.1");
	myUUID[2] = this->get("UUID.2");
	myUUID[3] = this->get("UUID.3");
    myUUID[4] = this->get("UUID.4");
	myUUID[5] = this->get("UUID.5");
	myUUID[6] = this->get("UUID.6");
    myUUID[7] = this->get("UUID.7");
	myUUID[8] = this->get("UUID.8");
	myUUID[9] = this->get("UUID.9");
    
    return;
}

void MCPParms::store(std::string &mystore)
{
    
    mystore = this->get("mcp.store");
    
    return;
}

void MCPParms::share(std::string &myshare)
{
    
    myshare = this->get("mcp.share");
    
    return;
}

int MCPParms::client()
/* 
    You would think this would be easy. But no.
    Here is the logic I used.... Broke it in steps to be clear
*/

{
    
    std::string myclientstr = this->get("mcp.client");
    int myclient = atoi(myclientstr.c_str()); // Crazy C++ code
    
    return myclient;
}

 
The spacing is better in the code. I am tired of trying to align this stuff in WordPress!

So we have added the needed items to begin the next step, actually passing files. I intend to have a file appear in the share directory, process it, accept it, move it to the store directory, and send back an acknowledgment​. That is the next step. I am having trouble finding a way to get a list of files in a directory and information on the files. It appears that this is not available in C++11 that I am using. I will keep digging.

We are about to step out into the interesting bits. I hope to at least have code that can see files next time.

I forgot to add that I wrote a program to create the XML file. That is how I get all the values into​ the file. When I get this running the file will be create once and then copied to the various systems with different client numbers.​

Is there time?

One of the items I will need is a wait function. I am used to having one in Arduino based C and Python 3.x, but this is new in C++ from what I can see from my searches of the web. So I thought I would cover it here for a short post.

There is a boost function for thread handling that can be used to do a wait. Apparently,​ the compile C++11 can also handle this in the build classes. As we are using AWS’s Cloud9 development enviroment, lets use the C++11 solution.

To code this you will need an Include of chrono and thread; this code will give you a 1/2 second sleep:

std::this_thread::sleep_for(std::chrono::milliseconds(500));

Again, we have to type std:: everywhere as that is the coding standard of the day. The definition of time is also enjoying extra typing with a whopper of stt::chrono::milliseconds. That is almost reaching silly. Almost.

I have not learned the thread safe coding stuff supplied now by C++11. More to learn one of these days.

Well I thought I would take the time to cover wait.

First Utility Program

Well,​ the spacing was better in my code. I have written a utility program to create the Master Control Program data, mcpmainbuild and all the other header and class files. The program just creates a new file, MCP.xml, with all of the text for the name for the program and then ten random newly minted UUID values. These will be shared with the other running copies. This allows for a cheap and easy proof of work (POW). Well here is the code, again the editor played havoc with the formatting.

int main()
{
    
	// Print a header of execution out
	auto result = std::time(nullptr);	
	std::cout << "Master Control Build Program " << std::endl;
	std::cout << "Local Time: " <<
	    std::asctime(std::localtime(&result)) << std::endl;
	    
	// Define our tree of data
	pt::ptree tree;
	    
    // Create program information
    tree.put("mcp", "mcpmain");
    tree.put("mcp.programtext", "Master Control Program");
    tree.put("mcp.version", "0.0.1");
    
	// Create ten UUID in the file 
	boost::uuids::random_generator generator;
    boost::uuids::uuid uuid1 = generator();
	tree.put("UUID.0", uuid1);
	uuid1 = generator();
	tree.put("UUID.1", uuid1);
    uuid1 = generator();
	tree.put("UUID.2", uuid1);
	uuid1 = generator();
	tree.put("UUID.3", uuid1);
	uuid1 = generator();
	tree.put("UUID.4", uuid1);
	uuid1 = generator();
	tree.put("UUID.5", uuid1);
    uuid1 = generator();
	tree.put("UUID.6", uuid1);
	uuid1 = generator();
	tree.put("UUID.7", uuid1);
	uuid1 = generator();
	tree.put("UUID.8", uuid1);
	uuid1 = generator();
	tree.put("UUID.9", uuid1);
	
	pt::write_xml("MCP.xml", tree);
    
    result = std::time(nullptr);
    std::cout << "Exit: Master Control Build Program " << std::endl;
	std::cout << "Local Time: " <<
	    std::asctime(std::localtime(&result)) << std::endl;
    
    
    // Leave politely
    return 0;

}

This program just declares a tree using the boost library cool code. It then builds some data in the tree. Lastly, it just writes out the UUID values. Nothing interesting really, but we need to start somewhere.

I will add another table creation for the base value of blockchain file and the run data that is different by instance. I have decided for now to allow up to ten instances of this new blockchain code. The first and master instance is zero and must always be running. It is the one that panic calls will be sent to. If this zero instance does not reply then the blockchain instances panic and shutdown. It is easier to have one instance, I think, play the primary while letting most functions be shared and passed around.

We are starting!

Once I get further we will start referring to GitHub code and not posting it here.

The run looks like this:

Running /home/ec2-user/environment/mcpbuildmain.cpp
Master Control Build Program
Local Time: Fri May 4 05:08:22 2018

Exit: Master Control Build Program
Local Time: Fri May 4 05:08:22 2018

Process exited with code: 0

Quick note on AWS

It is the beginning of May 2018. My bill of about a dollar came in from AWS. It appears that I am paying $0.011 an hour for compute and a tiny amount for storage. I am using the Cloud9 development servers, the “free” level. So yes free is about a buck a month. I figure if I was more full-time on this project I would pay about $70 a month. I have the system shutdown after 30 mins of inactivity to keep the costs down. The is recommended by AWS.

Just some facts for anyone out there looking at Cloud9, nice and not that expensive but not free.

More on UUID

Wrote a lot of code at work today so needed a bit of a break. Not much coding then tonight.

But–even tired, I was wondering about UUID and some code I did not understand. Please see the previous UUID post for more of the code. Here is the code that got my mind spinning:

boost::uuids::name_generator_sha1 mygen(boost::uuids::ns::dns());
boost::uuids::uuid udoc = mygen("To Be or not to be");
std::cout << "boost.org uuid in dns namespace, sha1 version: " << udoc << std::endl;
boost::uuids::name_generator_sha1 moregen(uuid2);
boost::uuids::uuid udoc2 = moregen("To Be or not to be");
std::cout << "boost.org uuid in random, sha1 version: " << udoc2 << std::endl;
boost::uuids::uuid udoc3 = moregen("To Be or not to be");
std::cout << "boost.org uuid in random, sha1 version: " << udoc3 << std::endl;

This code starts with defining the mygen function with a base value. It then uses a string to be the base to be turned into a UUID. A hashing of sorts. What I did not understand was that the definition defined a unique evaluation and this would create the same value for the same string. I also did not know that a different starting value would allow for a different value but always again the same value.

The execution of the code looks like this:

boost.org uuid in dns namespace, sha1 version: 49826646-175a-5fd8-9712-97f89d1e1ce3
boost.org uuid in random, sha1 version: 75255484-63d0-5332-addf-0bc4e551507c
boost.org uuid in random, sha1 version: 75255484-63d0-5332-addf-0bc4e551507c

This allows for me to create a cheap and easy proof-of-work (POW). I could pick a random UUID and share it between two implementations of the software. Each could then generate the same value, as long as they used sha1, for a given string like a random UUID. I could avoid cryptological code a bit longer. So UUIDs appear worthy of investing some code in.

I am thinking about storing some values in a table and also to compile in some values for UUID values. Specifically, I am thinking of an XML config table using the tree routines I covered in a previous post. I could including some shared UUID values. I was thinking of sharing ten values for a network​ of ten implementations with each one assigned a number. Number 0 would be a sort of master. Then I would also compile one value in for start-up and for crashes.

This was worth a second look.