fix bug related to FileId use; now safer due to separate node_from_id function
This was SVN commit r3605.
This commit is contained in:
parent
4b3997f1f6
commit
6e15ed1e82
@ -233,16 +233,16 @@ struct FileNode
|
|||||||
{
|
{
|
||||||
const char* atom_fn;
|
const char* atom_fn;
|
||||||
|
|
||||||
FileId prev : 15;
|
FileId prev_id;
|
||||||
|
FileId next_id;
|
||||||
u32 visited : 1;
|
u32 visited : 1;
|
||||||
FileId next : 15;
|
|
||||||
u32 output : 1;
|
u32 output : 1;
|
||||||
|
|
||||||
FileNode(const char* atom_fn_)
|
FileNode(const char* atom_fn_)
|
||||||
{
|
{
|
||||||
atom_fn = atom_fn_;
|
atom_fn = atom_fn_;
|
||||||
|
|
||||||
prev = next = NULL_ID;
|
prev_id = next_id = NULL_ID;
|
||||||
visited = output = 0;
|
visited = output = 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -276,6 +276,12 @@ public:
|
|||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FileNode* node_from_id(FileId id) const
|
||||||
|
{
|
||||||
|
debug_assert(id != NULL_ID);
|
||||||
|
return &(*nodes)[id-1];
|
||||||
|
}
|
||||||
|
|
||||||
FileId id_from_fn(const char* atom_fn) const
|
FileId id_from_fn(const char* atom_fn) const
|
||||||
{
|
{
|
||||||
Map::const_iterator cit = map.find(atom_fn);
|
Map::const_iterator cit = map.find(atom_fn);
|
||||||
@ -567,25 +573,22 @@ class TourBuilder
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// not const because we change the graph-related members
|
|
||||||
FileNodes& file_nodes;
|
|
||||||
|
|
||||||
bool has_cycle;
|
bool has_cycle;
|
||||||
void detect_cycleR(FileId node)
|
void detect_cycleR(FileId id)
|
||||||
{
|
{
|
||||||
FileNode* pnode = &file_nodes[node];
|
FileNode* pnode = id_mgr.node_from_id(id);
|
||||||
pnode->visited = 1;
|
pnode->visited = 1;
|
||||||
FileId next = pnode->next;
|
FileId next_id = pnode->next_id;
|
||||||
if(next != NULL_ID)
|
if(next_id != NULL_ID)
|
||||||
{
|
{
|
||||||
FileNode* pnext = &file_nodes[next];
|
FileNode* pnext = id_mgr.node_from_id(next_id);
|
||||||
if(pnext->visited)
|
if(pnext->visited)
|
||||||
has_cycle = true;
|
has_cycle = true;
|
||||||
else
|
else
|
||||||
detect_cycleR(next);
|
detect_cycleR(next_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bool is_cycle_at(FileId node)
|
bool is_cycle_at(FileNodes& file_nodes, FileId node)
|
||||||
{
|
{
|
||||||
has_cycle = false;
|
has_cycle = false;
|
||||||
for(FileNodes::iterator it = file_nodes.begin(); it != file_nodes.end(); ++it)
|
for(FileNodes::iterator it = file_nodes.begin(); it != file_nodes.end(); ++it)
|
||||||
@ -594,36 +597,34 @@ class TourBuilder
|
|||||||
return has_cycle;
|
return has_cycle;
|
||||||
}
|
}
|
||||||
|
|
||||||
void try_add_edge(const Connection& c)
|
void try_add_edge(FileNodes& file_nodes, const Connection& c)
|
||||||
{
|
{
|
||||||
FileId first_id = cid_first(c.id);
|
FileId first_id = cid_first(c.id);
|
||||||
FileId second_id = cid_second(c.id);
|
FileId second_id = cid_second(c.id);
|
||||||
|
|
||||||
FileNode& first = file_nodes[first_id];
|
FileNode* first = id_mgr.node_from_id(first_id);
|
||||||
FileNode& second = file_nodes[second_id];
|
FileNode* second = id_mgr.node_from_id(second_id);
|
||||||
// one of them has already been hooked up - bail
|
// one of them has already been hooked up - bail
|
||||||
if(first.next != NULL_ID || second.prev != NULL_ID)
|
if(first->next_id != NULL_ID || second->prev_id != NULL_ID)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
first.next = second_id;
|
first->next_id = second_id;
|
||||||
second.prev = first_id;
|
second->prev_id = first_id;
|
||||||
|
|
||||||
const bool introduced_cycle = is_cycle_at(second_id);
|
const bool introduced_cycle = is_cycle_at(file_nodes, second_id);
|
||||||
debug_assert(introduced_cycle == is_cycle_at(first_id));
|
debug_assert(introduced_cycle == is_cycle_at(file_nodes, first_id));
|
||||||
if(introduced_cycle)
|
if(introduced_cycle)
|
||||||
{
|
{
|
||||||
// undo
|
// undo
|
||||||
first.next = second.prev = NULL_ID;
|
first->next_id = second->prev_id = NULL_ID;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// pointer to this is returned by TourBuilder()!
|
|
||||||
std::vector<const char*>& fn_vector;
|
|
||||||
|
|
||||||
void output_chain(FileNode& node)
|
void output_chain(FileNode& node, std::vector<const char*>& fn_vector)
|
||||||
{
|
{
|
||||||
// early out: if this access was already visited, so must the entire
|
// early out: if this access was already visited, so must the entire
|
||||||
// chain of which it is a part. bail to save lots of time.
|
// chain of which it is a part. bail to save lots of time.
|
||||||
if(node.output)
|
if(node.output)
|
||||||
return;
|
return;
|
||||||
@ -631,34 +632,34 @@ class TourBuilder
|
|||||||
// follow prev links starting with c until no more are left;
|
// follow prev links starting with c until no more are left;
|
||||||
// start ends up the beginning of the chain including <c>.
|
// start ends up the beginning of the chain including <c>.
|
||||||
FileNode* start = &node;
|
FileNode* start = &node;
|
||||||
while(start->prev != NULL_ID)
|
while(start->prev_id != NULL_ID)
|
||||||
start = &file_nodes[start->prev];
|
start = id_mgr.node_from_id(start->prev_id);
|
||||||
|
|
||||||
// iterate over the chain - add to Filenames list and mark as visited
|
// iterate over the chain - add to Filenames list and mark as visited
|
||||||
FileNode* cur = start;
|
FileNode* cur = start;
|
||||||
do
|
for(;;)
|
||||||
{
|
{
|
||||||
if(!cur->output)
|
if(!cur->output)
|
||||||
{
|
{
|
||||||
fn_vector.push_back(cur->atom_fn);
|
fn_vector.push_back(cur->atom_fn);
|
||||||
cur->output = 1;
|
cur->output = 1;
|
||||||
}
|
}
|
||||||
cur = &file_nodes[cur->next];
|
if(cur->next_id == NULL_ID)
|
||||||
|
break;
|
||||||
|
cur = id_mgr.node_from_id(cur->next_id);
|
||||||
}
|
}
|
||||||
while(cur->next != NULL_ID);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TourBuilder(FileNodes& file_nodes_, Connections& connections, std::vector<const char*>& fns_)
|
TourBuilder(FileNodes& file_nodes, Connections& connections, std::vector<const char*>& fn_vector)
|
||||||
: file_nodes(file_nodes_), fn_vector(fns_)
|
|
||||||
{
|
{
|
||||||
std::sort(connections.begin(), connections.end(), Occurrence_greater());
|
std::stable_sort(connections.begin(), connections.end(), Occurrence_greater());
|
||||||
|
|
||||||
for(Connections::iterator it = connections.begin(); it != connections.end(); ++it)
|
for(Connections::iterator it = connections.begin(); it != connections.end(); ++it)
|
||||||
try_add_edge(*it);
|
try_add_edge(file_nodes, *it);
|
||||||
|
|
||||||
for(FileNodes::iterator it = file_nodes.begin(); it != file_nodes.end(); ++it)
|
for(FileNodes::iterator it = file_nodes.begin(); it != file_nodes.end(); ++it)
|
||||||
output_chain(*it);
|
output_chain(*it, fn_vector);
|
||||||
}
|
}
|
||||||
|
|
||||||
// should never be copied; this also squelches warning
|
// should never be copied; this also squelches warning
|
||||||
@ -705,12 +706,6 @@ archive.insert(atom_fn);
|
|||||||
static bool should_rebuild_main_archive(const char* P_archive_path,
|
static bool should_rebuild_main_archive(const char* P_archive_path,
|
||||||
const char* trace_filename)
|
const char* trace_filename)
|
||||||
{
|
{
|
||||||
std::vector<const char*> diff;
|
|
||||||
set_difference(loose.begin(), loose.end(), archive.begin(), archive.end(), back_inserter(diff));
|
|
||||||
debug_printf("loose only:\n");
|
|
||||||
for(std::vector<const char*>::iterator it = diff.begin(); it != diff.end(); ++it)
|
|
||||||
debug_printf("%s\n", *it);
|
|
||||||
|
|
||||||
// if there's no trace file, no point in building a main archive.
|
// if there's no trace file, no point in building a main archive.
|
||||||
struct stat s;
|
struct stat s;
|
||||||
if(file_stat(trace_filename, &s) != ERR_OK)
|
if(file_stat(trace_filename, &s) != ERR_OK)
|
||||||
@ -720,7 +715,6 @@ static bool should_rebuild_main_archive(const char* P_archive_path,
|
|||||||
if(s.st_mtime >= vfs_mtime)
|
if(s.st_mtime >= vfs_mtime)
|
||||||
trace_enable(false);
|
trace_enable(false);
|
||||||
|
|
||||||
|
|
||||||
const ssize_t loose_files_only = loose_file_total - non_loose_file_total;
|
const ssize_t loose_files_only = loose_file_total - non_loose_file_total;
|
||||||
if(loose_files_only >= REBUILD_MAIN_ARCHIVE_THRESHOLD)
|
if(loose_files_only >= REBUILD_MAIN_ARCHIVE_THRESHOLD)
|
||||||
return true;
|
return true;
|
||||||
@ -761,6 +755,7 @@ static void vfs_opt_init(const char* P_archive_fn_fmt, const char* trace_filenam
|
|||||||
fn_vector.push_back(0);
|
fn_vector.push_back(0);
|
||||||
Filenames V_fns = &fn_vector[0];
|
Filenames V_fns = &fn_vector[0];
|
||||||
|
|
||||||
|
|
||||||
char archive_fn[PATH_MAX];
|
char archive_fn[PATH_MAX];
|
||||||
static NextNumberedFilenameInfo archive_nfi;
|
static NextNumberedFilenameInfo archive_nfi;
|
||||||
next_numbered_filename(P_archive_fn_fmt, &archive_nfi, archive_fn, false);
|
next_numbered_filename(P_archive_fn_fmt, &archive_nfi, archive_fn, false);
|
||||||
|
Loading…
Reference in New Issue
Block a user