Commit 83cfa8ec authored by Robert Ricci's avatar Robert Ricci

Major changes to the way assign handles LAN nodes.

LAN nodes are no longer treated specially. Instead, I've introduced
the idea of 'static' types (old-style types retroactively become
'dynamic' types). While a pnode can only satisfy one dynamic type at a
time, it can always satisfy its static types (assuming it has enough
capacity left.) Static types are flagged by prepending them with a '*'
in the ptop file. So, for example, you may give switches the
'*lan:10000' type so that they can satisfy virtual LAN nodes. Of
course, other pnodes can have this type too, so that we can get
'trivial LANs'.

Actually, removing special treatment for LANs cleans up a lot of code.
However, it may have some negative impacts on solutions, since we're
not as smart about where to place LAN nodes as we used to be (they get
annealed along with everything else, and not migrated.) I haven't seen
any evidence of this yet, however.

This leaves us with a single type of special pnode, a switch.

Also added a new bit of syntax in ptop files - when '*' is given as a
the maxiumum load for a type, the node is allowed to take on an
infinite (well, actually, just a really big number of) vnodes of that
type.

ptopgen was modified to always report switches as being capable of
hosting LANs, and assign_wrapper now understands direct links to LANs,
which is what we get when the LAN is hosted directly on a switch.

Fixed a bug in scoring direct links, in which the penatly was being
added once when a direct link was mapped, but subtracted only once
when it was freed.

Added a '-T' option for doing simple self-testing. When adding a node
to the solution, assign records the score, adds the node, removes it
again, and checks to make sure that the resulting score is the same as
the original score. The usefulness of this feature in debugging
scoring problems cannot be understated...
parent 84ff51eb
...@@ -48,6 +48,18 @@ inline int accept(double change, double temperature) ...@@ -48,6 +48,18 @@ inline int accept(double change, double temperature)
return 0; return 0;
} }
// finds a random pnode, of any type at all
tb_pnode *find_random_pnode() {
int choice = std::random() % num_vertices(PG);
pvertex_iterator vit, vendit;
tie(vit,vendit) = vertices(PG);
cout << "Chose pnode " << choice << " of " << num_vertices(PG) << endl;
for (int i = 0; i < choice;++vit, ++i) {
}
tb_pnode *curP = get(pvertex_pmap,*vit);
return curP;
}
tb_pnode *find_pnode(tb_vnode *vn) tb_pnode *find_pnode(tb_vnode *vn)
{ {
#ifdef PER_VNODE_TT #ifdef PER_VNODE_TT
...@@ -67,7 +79,6 @@ tb_pnode *find_pnode(tb_vnode *vn) ...@@ -67,7 +79,6 @@ tb_pnode *find_pnode(tb_vnode *vn)
#ifdef PCLASS_SIZE_BALANCE #ifdef PCLASS_SIZE_BALANCE
int acceptchance = 1000 * (*acceptable_types)[i]->size * 1.0 / int acceptchance = 1000 * (*acceptable_types)[i]->size * 1.0 /
npnodes; npnodes;
//cout << "Chance was " << acceptchance << endl;
if ((std::rand() % 1000) < acceptchance) { if ((std::rand() % 1000) < acceptchance) {
continue; continue;
} }
...@@ -119,7 +130,8 @@ REDO_SEARCH: ...@@ -119,7 +130,8 @@ REDO_SEARCH:
} }
#else #else
if ((*it)->typed && ((*it)->current_type.compare(vn->type) || if ((*it)->typed && ((*it)->current_type.compare(vn->type) ||
((*it)->current_load >= (*it)->max_load))) { ((*it)->current_type_record->current_load >=
(*it)->current_type_record->max_load))) {
it++; it++;
} else { } else {
break; break;
...@@ -164,7 +176,7 @@ REDO_SEARCH: ...@@ -164,7 +176,7 @@ REDO_SEARCH:
/* When this is finished the state will reflect the best solution found. */ /* When this is finished the state will reflect the best solution found. */
void anneal() void anneal(bool scoring_selftest)
{ {
cout << "Annealing." << endl; cout << "Annealing." << endl;
...@@ -213,6 +225,10 @@ void anneal() ...@@ -213,6 +225,10 @@ void anneal()
/* Set up the initial counts */ /* Set up the initial counts */
init_score(); init_score();
/* We'll check against this later to make sure that whe we've unmapped
* everything, the score is the same */
double initial_score = get_score();
/* Set up fixed nodes */ /* Set up fixed nodes */
for (name_name_map::iterator fixed_it=fixed_nodes.begin(); for (name_name_map::iterator fixed_it=fixed_nodes.begin();
fixed_it!=fixed_nodes.end();++fixed_it) { fixed_it!=fixed_nodes.end();++fixed_it) {
...@@ -383,12 +399,7 @@ void anneal() ...@@ -383,12 +399,7 @@ void anneal()
} else { } else {
int start = std::random()%nnodes; int start = std::random()%nnodes;
int choice = start; int choice = start;
#if defined(FIX_LAN_NODES) || defined(AUTO_MIGRATE)
while (get(vvertex_pmap,virtual_nodes[choice])->fixed ||
!get(vvertex_pmap,virtual_nodes[choice])->type.compare("lan")) {
#else
while (get(vvertex_pmap,virtual_nodes[choice])->fixed) { while (get(vvertex_pmap,virtual_nodes[choice])->fixed) {
#endif
choice = (choice +1) % nnodes; choice = (choice +1) % nnodes;
if (choice == start) { if (choice == start) {
choice = -1; choice = -1;
...@@ -423,21 +434,6 @@ void anneal() ...@@ -423,21 +434,6 @@ void anneal()
vn->vclass->dominant << endl; vn->vclass->dominant << endl;
#endif #endif
} }
if (vn->type.compare("lan") == 0) {
// LAN node
pvertex lanv = make_lan_node(vv);
#ifndef FREE_IMMEDIATELY
if (oldassigned) {
RDEBUG(cout << "removing: lan,oldassigned" << endl;)
remove_node(vv);
}
#endif
if (add_node(vv,lanv,false) != 0) {
delete_lan_node(lanv);
unassigned_nodes.push(vvertex_int_pair(vv,std::random()));
continue;
}
} else {
tb_pnode *newpnode = find_pnode(vn); tb_pnode *newpnode = find_pnode(vn);
#ifndef FREE_IMMEDIATELY #ifndef FREE_IMMEDIATELY
if (oldassigned) { if (oldassigned) {
...@@ -506,11 +502,6 @@ void anneal() ...@@ -506,11 +502,6 @@ void anneal()
#else #else
int start = std::random()%nnodes; int start = std::random()%nnodes;
int toremove = start; int toremove = start;
#if defined(FIX_LAN_NODES) || defined(AUTO_MIGRATE)
while (get(vvertex_pmap,virtual_nodes[toremove])->fixed ||
(!get(vvertex_pmap,virtual_nodes[toremove])->assigned) ||
(get(vvertex_pmap,virtual_nodes[toremove])->type.compare("lan"))) {
#else
#ifdef SMART_UNMAP #ifdef SMART_UNMAP
#ifdef PER_VNODE_TT #ifdef PER_VNODE_TT
...@@ -547,7 +538,6 @@ void anneal() ...@@ -547,7 +538,6 @@ void anneal()
#else #else
while (get(vvertex_pmap,virtual_nodes[toremove])->fixed || while (get(vvertex_pmap,virtual_nodes[toremove])->fixed ||
(! get(vvertex_pmap,virtual_nodes[toremove])->assigned)) { (! get(vvertex_pmap,virtual_nodes[toremove])->assigned)) {
#endif
#endif #endif
toremove = (toremove +1) % nnodes; toremove = (toremove +1) % nnodes;
if (toremove == start) { if (toremove == start) {
...@@ -570,6 +560,16 @@ void anneal() ...@@ -570,6 +560,16 @@ void anneal()
#endif #endif
if (newpnode != NULL) { if (newpnode != NULL) {
newpos = pnode2vertex[newpnode]; newpos = pnode2vertex[newpnode];
if (scoring_selftest) {
// Run a little test here - see if the score we get by adding
// this node, then removing it, is the same one we would have
// gotten otherwise
double oldscore = get_score();
if (!add_node(vv,newpos,false)) {
remove_node(vv);
}
assert(oldscore == get_score());
}
if (add_node(vv,newpos,false) != 0) { if (add_node(vv,newpos,false) != 0) {
unassigned_nodes.push(vvertex_int_pair(vv,std::random())); unassigned_nodes.push(vvertex_int_pair(vv,std::random()));
continue; continue;
...@@ -584,31 +584,6 @@ void anneal() ...@@ -584,31 +584,6 @@ void anneal()
} }
#ifndef SMART_UNMAP #ifndef SMART_UNMAP
} }
#endif
}
#ifdef FIX_LAN_NODES
// OK, we're going to do something silly here: Migrate LAN nodes!
vvertex_iterator lanvertex_it,end_lanvertex_it;
vvertex_list migrate_lan_nodes;
tie(lanvertex_it,end_lanvertex_it) = vertices(VG);
for (;lanvertex_it!=end_lanvertex_it;++lanvertex_it) {
tb_vnode *vnode = get(vvertex_pmap,*lanvertex_it);
if (vnode->assigned) {
if (vnode->type.compare("lan") == 0) {
migrate_lan_nodes.push_front(*lanvertex_it);
}
}
}
while (migrate_lan_nodes.size() > 0) {
vvertex lanv = migrate_lan_nodes.front();
migrate_lan_nodes.pop_front();
RDEBUG(cout << "removing: migration" << endl;)
remove_node(lanv);
pvertex lanpv = make_lan_node(lanv);
add_node(lanv,lanpv,true);
}
#endif #endif
newscore = get_score(); newscore = get_score();
...@@ -717,9 +692,6 @@ void anneal() ...@@ -717,9 +692,6 @@ void anneal()
RDEBUG(cout << "removing: rejected change" << endl;) RDEBUG(cout << "removing: rejected change" << endl;)
remove_node(vv); remove_node(vv);
if (oldassigned) { if (oldassigned) {
if (vn->type.compare("lan") == 0) {
oldpos = make_lan_node(vv);
}
add_node(vv,oldpos,false); add_node(vv,oldpos,false);
} }
} }
...@@ -904,18 +876,7 @@ NOTQUITEDONE: ...@@ -904,18 +876,7 @@ NOTQUITEDONE:
// Only revert if the best configuration has better violations // Only revert if the best configuration has better violations
vvertex_list lan_nodes; vvertex_list lan_nodes;
vvertex_iterator vvertex_it,end_vvertex_it; vvertex_iterator vvertex_it,end_vvertex_it;
if (!revert) { if (revert) {
// Just find LAN nodes, for migration
tie(vvertex_it,end_vvertex_it) = vertices(VG);
for (;vvertex_it!=end_vvertex_it;++vvertex_it) {
tb_vnode *vnode = get(vvertex_pmap,*vvertex_it);
if (vnode->assigned) {
if (vnode->type.compare("lan") == 0) {
lan_nodes.push_front(*vvertex_it);
}
}
}
} else {
cout << "Reverting to best solution\n"; cout << "Reverting to best solution\n";
// Do a full revert // Do a full revert
tie(vvertex_it,end_vvertex_it) = vertices(VG); tie(vvertex_it,end_vvertex_it) = vertices(VG);
...@@ -929,14 +890,20 @@ NOTQUITEDONE: ...@@ -929,14 +890,20 @@ NOTQUITEDONE:
RDEBUG(cout << "not removing: revert " << vnode->name << endl;) RDEBUG(cout << "not removing: revert " << vnode->name << endl;)
} }
} }
// Check to make sure that our 'clean' solution scores the same as
// the initial score - if not, that indicates a bug
if (get_score() != initial_score) {
cerr << "*** WARNING: 'Clean' score does not match initial score" <<
endl << " This indicates a bug - contact the operators" <<
endl << " (initial score: " << initial_score <<
", current score: " << get_score() << ")" << endl;
}
tie(vvertex_it,end_vvertex_it) = vertices(VG); tie(vvertex_it,end_vvertex_it) = vertices(VG);
for (;vvertex_it!=end_vvertex_it;++vvertex_it) { for (;vvertex_it!=end_vvertex_it;++vvertex_it) {
tb_vnode *vnode = get(vvertex_pmap,*vvertex_it); tb_vnode *vnode = get(vvertex_pmap,*vvertex_it);
if (vnode->fixed) continue; if (vnode->fixed) continue;
if (absassigned[*vvertex_it]) { if (absassigned[*vvertex_it]) {
if (vnode->type.compare("lan") == 0) {
lan_nodes.push_front(*vvertex_it);
} else {
if (vnode->vclass != NULL) { if (vnode->vclass != NULL) {
vnode->type = abstypes[*vvertex_it]; vnode->type = abstypes[*vvertex_it];
} }
...@@ -944,20 +911,6 @@ NOTQUITEDONE: ...@@ -944,20 +911,6 @@ NOTQUITEDONE:
} }
} }
} }
}
// Do LAN migration
RDEBUG(cout << "Doing LAN migration" << endl;)
while (lan_nodes.size() > 0) {
vvertex lanv = lan_nodes.front();
lan_nodes.pop_front();
if (!revert) { // If reverting, we've already done this
RDEBUG(cout << "removing: migration" << endl;)
remove_node(lanv);
}
pvertex lanpv = make_lan_node(lanv);
add_node(lanv,lanpv,true);
}
tsteps++; tsteps++;
......
...@@ -80,8 +80,6 @@ inline int accept(double change, double temperature); ...@@ -80,8 +80,6 @@ inline int accept(double change, double temperature);
tb_pnode *find_pnode(tb_vnode *vn); tb_pnode *find_pnode(tb_vnode *vn);
/* The big guy! */ /* The big guy! */
void anneal(); void anneal(bool scoring_selftest);
#endif #endif
...@@ -298,6 +298,7 @@ void print_help() ...@@ -298,6 +298,7 @@ void print_help()
#ifdef PER_VNODE_TT #ifdef PER_VNODE_TT
cerr << " -P - Prune unusable pclasses." << endl; cerr << " -P - Prune unusable pclasses." << endl;
#endif #endif
cerr << " -T - Doing some scoring self-testing." << endl;
exit(2); exit(2);
} }
...@@ -312,11 +313,6 @@ int type_precheck() { ...@@ -312,11 +313,6 @@ int type_precheck() {
for (name_count_map::iterator vtype_it=vtypes.begin(); for (name_count_map::iterator vtype_it=vtypes.begin();
vtype_it != vtypes.end();++vtype_it) { vtype_it != vtypes.end();++vtype_it) {
// Ignore LAN vnodes
if (vtype_it->first == crope("lan")) {
continue;
}
// Check to see if there were any pnodes of the type at all // Check to see if there were any pnodes of the type at all
name_count_map::iterator ptype_it = ptypes.find(vtype_it->first); name_count_map::iterator ptype_it = ptypes.find(vtype_it->first);
if (ptype_it == ptypes.end()) { if (ptype_it == ptypes.end()) {
...@@ -366,11 +362,6 @@ int mapping_precheck() { ...@@ -366,11 +362,6 @@ int mapping_precheck() {
for (;vit != vendit;vit++) { for (;vit != vendit;vit++) {
tb_vnode *v = get(vvertex_pmap,*vit); tb_vnode *v = get(vvertex_pmap,*vit);
//
// No reason to do this work for LAN nodes!
if (!v->type.compare("lan")) {
continue;
}
pclass_vector *vec = new pclass_vector(); pclass_vector *vec = new pclass_vector();
vnode_type_table[v->name] = tt_entry(0,vec); vnode_type_table[v->name] = tt_entry(0,vec);
...@@ -405,8 +396,12 @@ int mapping_precheck() { ...@@ -405,8 +396,12 @@ int mapping_precheck() {
// Grab the first node of the pclass as a representative sample // Grab the first node of the pclass as a representative sample
tb_pnode *pnode = *((*it)->members[this_type]->L.begin()); tb_pnode *pnode = *((*it)->members[this_type]->L.begin());
// Check the number of interfaces // Check the number of interfaces - if the pnode is a switch,
if (pnode->total_interfaces >= v->num_links) { // for now, we don't check this, since it can end up with more
// 'interfaces' due to the fact that it can have interswitch
// links
if ((pnode->total_interfaces >= v->num_links) ||
pnode->current_type.compare("switch")) {
matched_links++; matched_links++;
} else { } else {
potential_match = false; potential_match = false;
...@@ -529,6 +524,7 @@ int main(int argc,char **argv) ...@@ -529,6 +524,7 @@ int main(int argc,char **argv)
{ {
int seed = 0; int seed = 0;
crope viz_prefix; crope viz_prefix;
bool scoring_selftest = false;
// Handle command line // Handle command line
char ch; char ch;
...@@ -566,6 +562,8 @@ int main(int argc,char **argv) ...@@ -566,6 +562,8 @@ int main(int argc,char **argv)
case 'P': case 'P':
prune_pclasses = true; break; prune_pclasses = true; break;
#endif #endif
case 'T':
scoring_selftest = true; break;
default: default:
print_help(); print_help();
} }
...@@ -653,8 +651,9 @@ int main(int argc,char **argv) ...@@ -653,8 +651,9 @@ int main(int argc,char **argv)
} }
timestart = used_time(); timestart = used_time();
anneal(); anneal(scoring_selftest);
timeend = used_time(); timeend = used_time();
#ifdef GNUPLOT_OUTPUT #ifdef GNUPLOT_OUTPUT
fclose(scoresout); fclose(scoresout);
fclose(tempout); fclose(tempout);
......
...@@ -63,20 +63,24 @@ Each vnode has a type and a valid solution must match each vnode to a ...@@ -63,20 +63,24 @@ Each vnode has a type and a valid solution must match each vnode to a
pnode that can support that type. A vnode has a single type but a pnode that can support that type. A vnode has a single type but a
pnode may be able to support several types and even have multiple pnode may be able to support several types and even have multiple
vnodes in a single vnode. For example, a standard testbed PC with vnodes in a single vnode. For example, a standard testbed PC with
four interfaces can either be a test node or up to two delay nodes. A four interfaces can either be a test node or up to two delay nodes.
pnode that has not been matched to a vnode is called virgin and can The type system is composed of two classes of types: 'dynamic' types,
take on any of its types. Once it has been mapped to a vnode it and 'static' types. A pnode can always satisfy any of its static
becomes typed and is locked into a certain type (that of the vnode). types, but has only one of its dynamic types 'active' at any time. A
When add_node is called the first thing checked is whether the pnode pnode that has not been matched to a vnode using one of its dynamic
has a suitable type for the vnode. If it is virgin then all its types types is called virgin and can take on any of its dynamic types. Once
are checked, otherwise only its current type is checked. If the types it has been mapped to a vnode it becomes typed and is locked into a
can not be matched then add_node returns an invalid condition, certain type (that of the vnode). When add_node is called the first
otherwise it continues on. thing checked is whether the pnode has a suitable type for the vnode.
If the vnode uses a static type, the pnode must simply have available
capacity for that type. Otherwise, dynamic types are checked. If it is
virgin then all its types are checked, otherwise only its current type
is checked. If the types can not be matched then add_node returns an
invalid condition, otherwise it continues on.
Each type of a pnode also has a limit. This is the number of vnodes Each type of a pnode also has a limit. This is the number of vnodes
of that type that can fit in the pnode. A vnode can not be placed in a pnode unless there is room left. of that type that can fit in the pnode. A vnode can not be placed in
a pnode unless there is room left.
Under no conditions is a vnode mapped to a switch.
Links Links
----- -----
......
...@@ -67,8 +67,18 @@ int parse_ptop(tb_pgraph &PG, tb_sgraph &SG, istream& i) ...@@ -67,8 +67,18 @@ int parse_ptop(tb_pgraph &PG, tb_sgraph &SG, istream& i)
if (split_two(parsed_line[i],':',type,load,"1") != 0) { if (split_two(parsed_line[i],':',type,load,"1") != 0) {
ptop_error("Bad node line, no load for type: " << type << "."); ptop_error("Bad node line, no load for type: " << type << ".");
} }
// Check to see if this is a static type
bool is_static = false;
if (type[0] == '*') {
is_static = true;
type.pop_front();
}
int iload; int iload;
if (sscanf(load.c_str(),"%d",&iload) != 1) { if (!load.compare("*")) { // Allow * to mean unlimited
// (okay, a really big number)
iload = 10000000;
} else if (sscanf(load.c_str(),"%d",&iload) != 1) {
ptop_error("Bad node line, bad load: " << load << "."); ptop_error("Bad node line, bad load: " << load << ".");
iload = 1; iload = 1;
} }
...@@ -79,14 +89,14 @@ int parse_ptop(tb_pgraph &PG, tb_sgraph &SG, istream& i) ...@@ -79,14 +89,14 @@ int parse_ptop(tb_pgraph &PG, tb_sgraph &SG, istream& i)
} }
if (type.compare("switch") == 0) { if (type.compare("switch") == 0) {
isswitch = true; isswitch = true;
p->types["switch"] = 1; p->types["switch"] = new tb_pnode::type_record(1,false);
svertex sv = add_vertex(SG); svertex sv = add_vertex(SG);
tb_switch *s = new tb_switch(); tb_switch *s = new tb_switch();
put(svertex_pmap,sv,s); put(svertex_pmap,sv,s);
s->mate = pv; s->mate = pv;
p->sgraph_switch = sv; p->sgraph_switch = sv;
} else { } else {
p->types[type] = iload; p->types[type] = new tb_pnode::type_record(iload,is_static);
} }
} }
for (i=i+1;(i<parsed_line.size()) && (parsed_line[i].compare("-")) ;++i) { for (i=i+1;(i<parsed_line.size()) && (parsed_line[i].compare("-")) ;++i) {
...@@ -103,7 +113,7 @@ int parse_ptop(tb_pgraph &PG, tb_sgraph &SG, istream& i) ...@@ -103,7 +113,7 @@ int parse_ptop(tb_pgraph &PG, tb_sgraph &SG, istream& i)
p->features[feature] = gcost; p->features[feature] = gcost;
} }
/* /*
* Parse any other node optios or flags * Parse any other node options or flags
*/ */
for (i=i+1; i < parsed_line.size(); ++i) { for (i=i+1; i < parsed_line.size(); ++i) {
crope flag,value; crope flag,value;
...@@ -215,10 +225,11 @@ int parse_ptop(tb_pgraph &PG, tb_sgraph &SG, istream& i) ...@@ -215,10 +225,11 @@ int parse_ptop(tb_pgraph &PG, tb_sgraph &SG, istream& i)
pl->type = tb_plink::PLINK_INTERSWITCH; pl->type = tb_plink::PLINK_INTERSWITCH;
} }
} }
srcnode->total_interfaces++;
dstnode->total_interfaces++;
if (ISSWITCH(srcnode) && if (ISSWITCH(srcnode) &&
! ISSWITCH(dstnode)) { ! ISSWITCH(dstnode)) {
dstnode->switches.insert(srcv); dstnode->switches.insert(srcv);
dstnode->total_interfaces++;
#ifdef PER_VNODE_TT #ifdef PER_VNODE_TT
dstnode->total_bandwidth += ibw; dstnode->total_bandwidth += ibw;
#endif #endif
...@@ -226,7 +237,6 @@ int parse_ptop(tb_pgraph &PG, tb_sgraph &SG, istream& i) ...@@ -226,7 +237,6 @@ int parse_ptop(tb_pgraph &PG, tb_sgraph &SG, istream& i)
else if (ISSWITCH(dstnode) && else if (ISSWITCH(dstnode) &&
! ISSWITCH(srcnode)) { ! ISSWITCH(srcnode)) {
srcnode->switches.insert(dstv); srcnode->switches.insert(dstv);
srcnode->total_interfaces++;
#ifdef PER_VNODE_TT #ifdef PER_VNODE_TT
srcnode->total_bandwidth += ibw; srcnode->total_bandwidth += ibw;
#endif #endif
......
...@@ -66,10 +66,10 @@ int pclass_equiv(tb_pgraph &PG, tb_pnode *a,tb_pnode *b) ...@@ -66,10 +66,10 @@ int pclass_equiv(tb_pgraph &PG, tb_pnode *a,tb_pnode *b)
for (tb_pnode::types_map::iterator it=a->types.begin(); for (tb_pnode::types_map::iterator it=a->types.begin();
it!=a->types.end();++it) { it!=a->types.end();++it) {
const crope &a_type = (*it).first; const crope &a_type = (*it).first;
const int a_max_nodes = (*it).second; tb_pnode::type_record *a_type_record = (*it).second;
tb_pnode::types_map::iterator bit = b->types.find(a_type); tb_pnode::types_map::iterator bit = b->types.find(a_type);
if ((bit == b->types.end()) ||((*bit).second != a_max_nodes)) if ((bit == b->types.end()) || ! ( *(*bit).second == *a_type_record) )
return 0; return 0;
} }
...@@ -222,7 +222,8 @@ int pclass_set(tb_vnode *v,tb_pnode *p) ...@@ -222,7 +222,8 @@ int pclass_set(tb_vnode *v,tb_pnode *p)
for (dit=c->members.begin();dit!=c->members.end();dit++) { for (dit=c->members.begin();dit!=c->members.end();dit++) {
if ((*dit).first == p->current_type) { if ((*dit).first == p->current_type) {
// same class - only remove if node is full // same class - only remove if node is full
if (p->current_load == p->max_load) { if (p->types[p->current_type]->current_load ==
p->types[p->current_type]->max_load) {
(*dit).second->remove(p); (*dit).second->remove(p);
//#ifdef SMART_UNMAP //#ifdef SMART_UNMAP
// c->used_members[(*dit).first]->push_back(p); // c->used_members[(*dit).first]->push_back(p);
...@@ -246,7 +247,7 @@ int pclass_set(tb_vnode *v,tb_pnode *p) ...@@ -246,7 +247,7 @@ int pclass_set(tb_vnode *v,tb_pnode *p)
} }
c->used += 1.0/(p->max_load); c->used += 1.0/(p->current_type_record->max_load);
return 0; return 0;
} }
...@@ -266,12 +267,12 @@ int pclass_unset(tb_pnode *p) ...@@ -266,12 +267,12 @@ int pclass_unset(tb_pnode *p)
// empty and the front if it's not. Since unset is called before // empty and the front if it's not. Since unset is called before
// remove_node empty means only one user. // remove_node empty means only one user.
if (! (*dit).second->exists(p)) { if (! (*dit).second->exists(p)) {
assert(p->current_load > 0); assert(p->types