blob: 34be9b5ea0e01ce4f4378e1c4747bf9a9f4f5383 [file] [log] [blame]
#ifndef _PRAGMA_COPYRIGHT_
#define _PRAGMA_COPYRIGHT_
#pragma comment(copyright, "%Z% %I% %W% %D% %T%\0")
#endif /* _PRAGMA_COPYRIGHT_ */
/****************************************************************************
* Copyright (c) 2008, 2010 IBM Corporation.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0s
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
Classes: BEMap
Description: Runtime BEMap.
Author: ronglli
History:
Date Who ID Description
-------- --- --- -----------
08/24/12 ronglli Initial code
****************************************************************************/
#include <stdlib.h>
#include <regex.h>
#include <fstream>
#include "sci.h"
#include "bemap.hpp"
#include "log.hpp"
#define BEMAP_SUCCESS 0
#define BEMAP_ERROR -1
#define BEMAP_FULL (-999999)
#define VALID_REGEX "^[^][%*]*(\\[[0-9]+-[0-9]+(:[0-9]+)?\\]){0,}[^][%*]*([*][0-9]+)?(%\\[(([0-9]+,){0,}[0-9]+|[0-9]+-[0-9]+(:[0-9]+)?)\\])?$"
int BEMap::input(const char *hostlist[], int num)
{
int i = 0;
while (hostlist[i] != NULL) {
if ((num > 0) && (i >= num)) {
break;
}
(*this)[i] = hostlist[i];
i++;
}
return SCI_SUCCESS;
}
int BEMap::input(const char * filename, int num)
{
int rc = -1;
ifstream fs;
string line;
size_t pos = -1;
int max_id, size;
fs.open(filename);
if (!fs) {
return SCI_ERR_INVALID_HOSTFILE;;
}
clear_lineinfo();
(*this).first_empty = 0;
log_debug("Hostlist is: ");
while(fs) {
if ((num > 0) && ((*this).size() >= num)) {
break;
}
getline(fs, line);
trim_whitespace(line);
if (line.length() == 0) {
continue;
}
if ((line.find_first_of('!') == 0) || (line.find_first_of('*') == 0)) {
continue;
}
rc = isValidForm(line, VALID_REGEX);
if (rc) {
return SCI_ERR_INVALID_HOSTFILE;
}
rc = expand_line(line, num);
if (rc == BEMAP_FULL) {
break;
} else if (rc != BEMAP_SUCCESS){
return SCI_ERR_INVALID_HOSTFILE;
}
clear_lineinfo();
}
fs.close();
size = (*this).size();
if (size == 0) {
log_error("BEMap error: empty host file.");
return SCI_ERR_INVALID_HOSTFILE;
}
max_id = ((*this).rbegin())->first;
if (max_id >= size) {
log_error("BEMap error: max_id(%d) needs to be smaller than the totalsize(%d)",
max_id, size);
return SCI_ERR_INVALID_HOSTFILE;
}
return SCI_SUCCESS;
}
int BEMap::trim_whitespace(string & line)
{
string::iterator it;
for (it = line.begin(); it != line.end();) {
if (isspace(*it))
it = line.erase(it);
else
it++;
}
return BEMAP_SUCCESS;
}
int BEMap::isValidForm(string line, const char * regex)
{
int rc = BEMAP_SUCCESS;
regex_t preg;
if((line.find_first_of('[') == string::npos) && (line.find_first_of('*') == string::npos)) {
if((line.find_first_of('%') == string::npos) && (line.find_first_of(':') == string::npos))
return rc;
}
rc = regcomp(&preg, regex, REG_EXTENDED|REG_NOSUB|REG_NEWLINE);
if(rc != 0) {
log_error("regcomp error, line:%s, rc = %d", line.c_str(), rc);
return BEMAP_ERROR;
}
rc = regexec(&preg, line.c_str(), 0, 0, 0);
if(rc != 0) {
log_error("regex NOT match, line:%s, rc = %d", line.c_str(), rc);
return BEMAP_ERROR;
}
return rc;
}
int BEMap::generate_host_range()
{
if (hostinfo.range_begin == -1) {
hostinfo.host_cnt = hostinfo.repetition;
} else {
int begin;
begin = hostinfo.range_begin;
while (begin <= hostinfo.range_end) {
hostinfo.expanded_range.push_back(begin);
hostinfo.host_cnt++;
begin += hostinfo.stride;
}
hostinfo.host_cnt *= hostinfo.repetition;
}
return BEMAP_SUCCESS;
}
int BEMap::generate_host_entries()
{
int i;
if (hostinfo.expanded_range.empty()) {
for (i = 0; i < hostinfo.repetition; i++) {
hostinfo.host_entries.push_back(hostinfo.front + hostinfo.end);
}
} else {
INT_VEC::iterator iter;
char buf[128], format[32];
sprintf(format, "%%0%dd%", hostinfo.range_digits);
for (iter = hostinfo.expanded_range.begin(); iter != hostinfo.expanded_range.end(); iter++) {
for (i = 0; i < hostinfo.repetition; i++) {
sprintf(buf, format, *iter);
hostinfo.host_entries.push_back(hostinfo.front + buf + hostinfo.end);
}
}
}
return BEMAP_SUCCESS;
}
int BEMap::expand_host_range(string range)
{
int pos = -1;
int pos1 = -1;
string tmps;
pos = range.find_first_of('-');
tmps = range.substr(0, pos);
hostinfo.range_begin = atoi(tmps.c_str());
hostinfo.range_digits = tmps.size();
pos1 = range.find_first_of(':', pos+1);
if (pos1 == string::npos) {
tmps = range.substr(pos+1);
hostinfo.range_end = atoi(tmps.c_str());
hostinfo.stride = 1;
} else {
tmps = range.substr(pos+1, pos1-pos-1);
hostinfo.range_end = atoi(tmps.c_str());
tmps = range.substr(pos1+1);
hostinfo.stride = atoi(tmps.c_str());
if (hostinfo.stride <= 0) {
log_error("stride is %d, it must >= 1", hostinfo.stride);
return BEMAP_ERROR;
}
}
if ((hostinfo.range_begin < 0) || hostinfo.range_end < 0) {
log_error("host part: both left side(%d) & right side(%d) of a range must >= 0",
hostinfo.range_begin, hostinfo.range_end);
return BEMAP_ERROR;
}
if (hostinfo.range_end < hostinfo.range_begin) {
log_error("host part: right side(%d) of a range must >= left side (%d) of a range",
hostinfo.range_end, hostinfo.range_begin);
return BEMAP_ERROR;
}
return BEMAP_SUCCESS;
}
int BEMap::expand_host_region(string hregion)
{
int rc = BEMAP_SUCCESS;
int pos = -1;
int left = -1;
int right = -1;
pos = hregion.find_first_of('*');
if (pos == string::npos) {
hostinfo.repetition = 1;
} else {
string tmps = hregion.substr(pos+1);
hostinfo.repetition = atoi(tmps.c_str());
}
if (hostinfo.repetition <= 0) {
log_error("repetition(%d) of hosts must >= 1", hostinfo.repetition);
return BEMAP_ERROR;
}
left = hregion.find_first_of('[');
right = hregion.find_first_of(']');
if ((left == string::npos) && (right == string::npos)) {
hostinfo.front = hregion.substr(0, pos);
hostinfo.end = "";
hostinfo.stride = 1;
hostinfo.range_begin = -1;
hostinfo.range_end = -1;
} else {
if ((left == string::npos) || (right == string::npos)) {
return BEMAP_ERROR;
}
hostinfo.front = hregion.substr(0, left);
if (pos == string::npos) {
hostinfo.end = hregion.substr(right+1);
} else {
hostinfo.end = hregion.substr(right+1, pos-right-1);
}
string range = hregion.substr(left+1, right-left-1);
rc = expand_host_range(range);
if (rc != 0) {
return BEMAP_ERROR;
}
}
generate_host_range();
generate_host_entries();
return BEMAP_SUCCESS;
}
int BEMap::generate_task_range()
{
if (taskinfo.range_begin == -1) {
taskinfo.task_cnt = taskinfo.free_form.size();
} else {
int begin;
begin = taskinfo.range_begin;
while(begin <= taskinfo.range_end) {
taskinfo.free_form.push_back(begin);
taskinfo.task_cnt++;
begin += taskinfo.stride;
}
}
return BEMAP_SUCCESS;
}
int BEMap::expand_task_region(string tregion)
{
int left = -1;
int right = -1;
int pos = -1;
int pos1 = -1;
string tmps;
left = tregion.find_first_of('[');
right = tregion.find_first_of(']');
if ((left == string::npos) || (right == string::npos)) {
log_error("task region: it must start with '[' and end with ']'");
return BEMAP_ERROR;
}
pos = tregion.find_first_of('-');
if (pos != string::npos) {
if ((pos < left) || (pos > right)) {
log_error("task region: the '-' must be between the '[' and ']'");
return BEMAP_ERROR;
}
tmps = tregion.substr(left+1, pos-left-1);
taskinfo.range_begin = atoi(tmps.c_str());
pos1 = tregion.find_first_of(':', pos+1);
if (pos1 == string::npos) {
tmps = tregion.substr(pos+1, right-pos-1);
taskinfo.range_end = atoi(tmps.c_str());
taskinfo.stride = 1;
} else {
tmps = tregion.substr(pos+1, pos1-pos-1);
taskinfo.range_end = atoi(tmps.c_str());
tmps = tregion.substr(pos1+1, right-pos1-1);
taskinfo.stride = atoi(tmps.c_str());
if (taskinfo.stride <= 0) {
log_error("task part: stride = %d, it must >= 1", taskinfo.stride);
return BEMAP_ERROR;
}
if ((taskinfo.range_begin < 0) || (taskinfo.range_end < 0)) {
log_error("task part: both sides of the range(%d, %d) must >=0",
taskinfo.range_begin, taskinfo.range_end);
return BEMAP_ERROR;
}
if (taskinfo.range_end < taskinfo.range_begin) {
log_error("task part: right side(%d) of a range must >= left side(%d) of a range",
taskinfo.range_end, taskinfo.range_begin);
return BEMAP_ERROR;
}
}
} else {
int tid;
int start = left;
pos1 = tregion.find_first_of(',');
if (pos1 != string::npos) {
do {
tmps = tregion.substr(start+1, pos1-start-1);
tid = atoi(tmps.c_str());
taskinfo.free_form.push_back(tid);
start = pos1;
pos1 = tregion.find_first_of(',', pos1+1);
} while (pos1 != string::npos);
}
tmps = tregion.substr(start+1, right-left-1);
tid = atoi(tmps.c_str());
taskinfo.free_form.push_back(tid);
}
if (generate_task_range() != 0) {
return BEMAP_ERROR;
}
return BEMAP_SUCCESS;
}
int BEMap::update_mapping(int num)
{
INT_VEC::iterator t_iter;
STRING_VEC::iterator h_iter;
if (taskinfo.task_cnt > 0) {
t_iter = taskinfo.free_form.begin();
h_iter = hostinfo.host_entries.begin();
for (; t_iter != taskinfo.free_form.end(); t_iter++, h_iter++) {
if (*t_iter < 0) {
log_error("task id(%d) must >= 0", *t_iter);
return BEMAP_ERROR;
}
if ((*this).find(*t_iter) != (*this).end()) {
log_error("error: duplicated task id(%d) for one job", *t_iter);
return BEMAP_ERROR;
}
if ((num > 0) && ((*this).size() >= num)) {
return BEMAP_FULL;
}
(*this)[*t_iter] = *h_iter;
log_debug("[%d]: %s", *t_iter, (*h_iter).c_str());
}
} else {
for (h_iter = hostinfo.host_entries.begin(); h_iter != hostinfo.host_entries.end(); h_iter++) {
int index;
bool found = false;
int max_id;
int size = (*this).size();
if ((num > 0) && (size >= num)) {
return BEMAP_FULL;
}
if (size > 0) {
max_id = ((*this).rbegin())->first;
for (index = (*this).first_empty; index < max_id; index++) {
if ((*this).find(index) == (*this).end()) {
found = true;
(*this).first_empty = index + 1;
break;
}
}
if (!found) {
index = max_id + 1;
}
} else {
index = 0;
(*this).first_empty = index + 1;
}
(*this)[index] = *h_iter;
log_debug("[%d]: %s", index, (*h_iter).c_str());
}
}
return BEMAP_SUCCESS;
}
int BEMap::expand_line(string line, int num)
{
int rc = BEMAP_SUCCESS;
int pos = -1;
string host_region;
string task_region;
pos = line.find_first_of('%');
if (pos != string::npos) {
host_region = line.substr(0, pos);
task_region = line.substr(pos+1);
} else {
host_region = line;
}
rc = expand_host_region(host_region);
if (rc != 0) {
return BEMAP_ERROR;
}
if (pos != string::npos) {
rc = expand_task_region(task_region);
if (rc != 0) {
return BEMAP_ERROR;
}
}
if (taskinfo.task_cnt > 0) {
if (hostinfo.host_cnt != taskinfo.task_cnt) {
log_error("host count(%d) and task count(%d) not match, current line:%s",
hostinfo.host_cnt, taskinfo.task_cnt, line.c_str());
return BEMAP_ERROR;
}
}
rc = update_mapping(num);
return rc;
}
int BEMap::clear_lineinfo()
{
hostinfo.front.clear();
hostinfo.end.clear();
hostinfo.host_cnt = 0;
hostinfo.repetition = 1;
hostinfo.stride = 1;
hostinfo.range_begin = -1;
hostinfo.range_end = -1;
hostinfo.range_digits = -1;
hostinfo.expanded_range.clear();
hostinfo.host_entries.clear();
taskinfo.task_cnt = 0;
taskinfo.free_form.clear();
taskinfo.range_begin = -1;
taskinfo.range_end = -1;
taskinfo.stride = 1;
return BEMAP_SUCCESS;
}
void BEMap::dump_mappings()
{
BEMap::iterator iter = (*this).begin();
log_debug("Hostlist is: ");
for (; iter != (*this).end(); iter++) {
log_debug("[%d]: %s", iter->first, iter->second.c_str());
}
}