Commit 0043c8b3 authored by Jonathon Duerig's avatar Jonathon Duerig

I've divided the program up into several files to make maintenance easier....

I've divided the program up into several files to make maintenance easier. Error checking and parsing has been added which allows the children processes to communicate errors in terms the user can understand. Finally, I've added an output option which to print a neato file which can be used to visualize the partitioning.
parent 48c5638c
// Partition.cc
/*
* EMULAB-COPYRIGHT
* Copyright (c) 2005 University of Utah and the Flux Group.
* All rights reserved.
*/
#include "prepass.h"
#include "Partition.h"
#include "coprocess.h"
//-----------------------------------------------------------------------------
Partition::Partition(int newNumber)
: address(0)
, isTree(true)
, lanCount(0)
, hostCount(0)
{
setNumber(newNumber);
}
//-----------------------------------------------------------------------------
void Partition::setNumber(int newNumber)
{
// TODO: Assign a real address. Not just the LAN number.
address = newNumber;
number = newNumber;
}
//-----------------------------------------------------------------------------
int Partition::getNumber(void) const
{
return number;
}
//-----------------------------------------------------------------------------
void Partition::setAddress(int newAddress)
{
address = newAddress;
}
//-----------------------------------------------------------------------------
int Partition::getAddress(void) const
{
return address;
}
//-----------------------------------------------------------------------------
void Partition::addLan(int lanNumber)
{
// Have we already added this LAN in the past?
map<int, int>::iterator lanSearch = lanToOrder.find(lanNumber);
if (lanSearch == lanToOrder.end())
{
// If not, add a mapping for the LAN.
lanToOrder[lanNumber] = lanCount;
orderToLan[lanCount] = lanNumber;
++lanCount;
isTree = isTree && g::allLans[lanNumber].isTreeRoot;
g::allLans[lanNumber].partition = number;
// Add one to the count of every host we touch. If two or more
// LANs touch a host, then that host is sent to the children
// as a hyper-edge. We just keep track of the count for
// now. Later we'll worry about filtering them.
list<string>::iterator pos = g::allLans[lanNumber].hosts.begin();
list<string>::iterator limit = g::allLans[lanNumber].hosts.end();
for (; pos != limit; ++pos)
{
++(hostToOrder[*pos].count);
}
}
}
//-----------------------------------------------------------------------------
template <class T>
void auto_assign(auto_ptr<T> & left, auto_ptr<T> right)
{
left = right;
}
//-----------------------------------------------------------------------------
void Partition::dispatch(void)
{
mapHosts();
auto_ptr<FileT> pipe;
if (isTree)
{
auto_assign(pipe, coprocess(g::treeCommand[0], &(g::treeCommand[0]),
NULL));
}
else
{
auto_assign(pipe, coprocess(g::generalCommand[0],
&(g::generalCommand[0]), NULL));
}
printGraph(pipe->input());
pipe->closeIn();
getNumbering(pipe->output());
int childReturn = 0;
int error = wait3(&childReturn, 0, NULL);
if (error == -1)
{
cerr << "Waiting for child failed: " << strerror(errno) << endl;
throw;
}
if (childReturn != 0)
{
parseError(pipe->error());
}
}
//-----------------------------------------------------------------------------
void Partition::parseError(istream & error)
{
cerr << "Error in partition " << number << ": ";
string outside;
string inside;
bool done;
getline(error, outside, '$');
done = !error;
while (!done)
{
cerr << outside;
getline(error, inside, '$');
bool hasInside = error;
if (hasInside && inside == "")
{
cerr << "$";
}
else if (hasInside)
{
size_t index = inside.find('=');
if (index != string::npos)
{
inside[index] = ' ';
}
istringstream buffer(inside);
string name;
int value = 0;
buffer >> name >> value;
if (!buffer)
{
buffer.clear();
string newVal;
buffer >> newVal;
cerr << "[META ERROR: INVALID VALUE: name(" << name
<< ") value(" << newVal << ")]";
}
else if (name == "vertex")
{
map<int, int>::iterator pos = orderToLan.find(value);
if (pos == orderToLan.end())
{
cerr << "[META ERROR: INVALID VERTEX NUMBER: name("
<< name << ") value(" << value << ")]";
}
else
{
cerr << pos->second;
}
}
else if (name == "edge")
{
map<int, string>::iterator pos = orderToHost.find(value);
if (pos == orderToHost.end())
{
cerr << "[META ERROR: INVALID EDGE NUMBER: name("
<< name << ") value(" << value << ")]";
}
else
{
cerr << pos->second;
}
}
else
{
cerr << "[META ERROR: INVALID NAME: name(" << name
<< ") value(" << value << ")]";
}
}
getline(error, outside, '$');
done = !error;
}
throw;
}
//-----------------------------------------------------------------------------
void Partition::printGraph(ostream & output)
{
output << "vertex-count " << lanCount << endl;
output << "edge-count " << hostCount << endl;
output << "total-bits " << 32 << endl;
output << "%%" << endl;
map<int, int>::iterator lanPos = orderToLan.begin();
map<int, int>::iterator lanLimit = orderToLan.end();
for (; lanPos != lanLimit; ++lanPos)
{
output << "8 1 ";
list<string>::iterator hostPos =
g::allLans[lanPos->second].hosts.begin();
list<string>::iterator hostLimit =
g::allLans[lanPos->second].hosts.end();
for (; hostPos != hostLimit; ++hostPos)
{
OrderCount oc = hostToOrder[*hostPos];
if (oc.count > 1)
{
output << oc.order << " ";
}
}
output << endl;
}
}
//-----------------------------------------------------------------------------
void Partition::getNumbering(istream & input)
{
int assignedNumber = 0;
int order = 0;
input >> assignedNumber;
while (input)
{
g::allLans[orderToLan[order]].assignment = assignedNumber;
input >> assignedNumber;
++order;
}
}
void Partition::mapHosts(void)
{
// For every host we've touched. If it has been touched by more
// than two LANs, then set up mapping information.
map<string, OrderCount>::iterator pos = hostToOrder.begin();
map<string, OrderCount>::iterator limit = hostToOrder.end();
for ( ; pos != limit; ++pos)
{
if (pos->second.count > 1)
{
pos->second.order = hostCount;
orderToHost[hostCount] = pos->first;
++hostCount;
}
}
}
//-----------------------------------------------------------------------------
// Partition.h
/*
* EMULAB-COPYRIGHT
* Copyright (c) 2005 University of Utah and the Flux Group.
* All rights reserved.
*/
#ifndef PARTITION_H_IPASSIGN_3
#define PARTITION_H_IPASSIGN_3
// The partition is a collection of all the information needed to
// output a sub-graph to a pipe and interpret the results.
class Partition
{
public:
Partition(int newNumber = 0);
void setNumber(int newNumber);
int getNumber(void) const;
void setAddress(int newAddress);
int getAddress(void) const;
// Add a lan to the information. This increases the count and adds
// the lan number to the mappings.
void addLan(int lanNumber);
void dispatch(void);
private:
struct OrderCount
{
OrderCount() : order(0), count(0) {}
int order;
int count;
};
private:
void mapHosts(void);
void printGraph(std::ostream & output);
void getNumbering(std::istream & input);
void parseError(std::istream & error);
private:
int number;
int address;
bool isTree;
int lanCount;
int hostCount;
// This provides a mappings back and forth from sub-program
// concepts to user concepts. We process our pipe output and then
// input based on these mappings.
std::map<int, int> lanToOrder;
std::map<int, int> orderToLan;
// The hostToOrder thing is a little different from the other
// mappings. In order to determine whether we want to count a host
// at all, we have to check to make sure that it touches two or
// more hosts. That is what the count attached to this is.
std::map<std::string, OrderCount> hostToOrder;
std::map<int, std::string> orderToHost;
};
#endif
g++ -o trivial-ipassign trivial-ipassign.cc
g++ -o prepass prepass.cc coprocess.cc
g++ -o fail-assign fail-assign.cc
g++ -o trivial-assign trivial-assign.cc
g++ -o prepass prepass.cc coprocess.cc Partition.cc
// fail-assign.cc
/*
* EMULAB-COPYRIGHT
* Copyright (c) 2005 University of Utah and the Flux Group.
* All rights reserved.
*/
#include <iostream>
#include <string>
using namespace std;
int main()
{
string line;
getline(cin, line);
getline(cin, line);
cerr << "Failed. Aborting on $$" << endl
<< "$vertex=0$" << endl
<< "$edge=0$" << endl
<< "$vertex=googly$" << endl
<< "$vertex=-1$" << endl
<< "$edge=1000000$" << endl
<< "$once upon a time$" << endl
<< "$first$" << endl
<< "$nonsense=3$" << endl;
return 1;
// string line;
// getline(cin, line);
// while (cin)
// {
// cerr << line << endl;
// getline(cin, line);
// }
// return 1;
}
This diff is collapsed.
// prepass.h
/*
* EMULAB-COPYRIGHT
* Copyright (c) 2005 University of Utah and the Flux Group.
* All rights reserved.
*/
#ifndef PREPASS_H_IPASSIGN_3
#define PREPASS_H_IPASSIGN_3
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
#include <list>
#include <map>
#include <cstdlib>
#include <signal.h>
#include <sys/wait.h>
struct Lan
{
Lan() : number(0),
partition(-1),
isNamingPoint(false),
isTreeRoot(false),
parentIndex(0),
assignment(0),
time (0) {}
// This is the index of the LAN in the great LAN array.
int number;
// The partition index number of the LAN.
int partition;
// A list of host keys used by the LAN.
std::list<std::string> hosts;
// Whether this LAN names a partition or not.
bool isNamingPoint;
// Whether this LAN is part of a tree or a cycle.
bool isTreeRoot;
// The index of the parent of this LAN in the DFS tree.
int parentIndex;
// The address assigned to this LAN. Used as part of the IP address.
int assignment;
// The time that this LAN was visited in the DFS tree.
int time;
// This is the hostname that is the edge currently being explored
// in the DFS tree. We must keep track of this to prevent the same
// edge being used more than once in a cycle.
//
// After finishing the sub-tree rooted at a host, we can ignore
// this because no other host can touch it to check the
// forwardEdge. Likewise, we need only concern ourselves with the
// current host we are exploring. Previously explored hosts will
// never be touched again.
std::string forwardEdge;
};
struct Host
{
Host() {}
std::string name;
std::list<int> lans;
};
class Partition;
namespace g
{
extern std::map<std::string, Host> allHosts;
extern std::vector<Lan> allLans;
extern std::vector<Partition> allPartitions;
extern std::vector<char*> treeCommand;
extern std::vector<char*> generalCommand;
extern bool useNeato;
}
void init(void);
void parseArgs(int argc, char * argv[]);
void parseSingleArg(char * arg);
void parseInput(void);
void addLan(int bits, int weights, vector<string> const & nodes);
void breakGraph(void);
void findNumbers(void);
void ouputAddresses(void);
void normalOutput(void);
void neatoOutput(void);
#endif
// trivial-ipassign.cc
// trivial-assign.cc
/*
* EMULAB-COPYRIGHT
* Copyright (c) 2005 University of Utah and the Flux Group.
* All rights reserved.
*/
#include <iostream>
#include <string>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment