40#ifndef ADSIDAC_PEOUTPUT_H
41#define ADSIDAC_PEOUTPUT_H
54namespace fs = std::filesystem;
71 const std::string& content) {
73 fs::create_directories(pe_dir, ec);
76 fout <<
"#PE " << branch_id <<
' ' << content.size() <<
'\n';
77 fout.write(content.data(),
static_cast<std::streamsize
>(content.size()));
89 std::vector<std::pair<int, std::string>>& out) {
90 std::ifstream fin(path, std::ios::binary);
93 while (std::getline(fin, line)) {
94 if (line.rfind(
"#PE ", 0) != 0)
continue;
95 std::istringstream hs(line.substr(4));
97 long long nbytes = -1;
98 if (!(hs >>
id >> nbytes) || nbytes < 0)
break;
99 std::string content(
static_cast<size_t>(nbytes),
'\0');
100 fin.read(&content[0], nbytes);
101 if (fin.gcount() != nbytes)
break;
103 out.emplace_back(
id, std::move(content));
124 std::vector<std::pair<int, std::string>> raw;
126 if (raw.empty())
return {0, 0};
127 std::map<int, std::string> latest;
128 for (
auto& [
id, content] : raw)
129 latest[id] = std::move(content);
130 if (latest.size() == raw.size())
return {raw.size(), latest.size()};
131 const fs::path tmp = agg_path.string() +
".compact";
133 std::ofstream fout(tmp, std::ios::binary | std::ios::trunc);
134 if (!fout)
return {raw.size(), latest.size()};
135 for (
auto& [
id, content] : latest) {
136 fout <<
"#PE " <<
id <<
' ' << content.size() <<
'\n';
137 fout.write(content.data(),
static_cast<std::streamsize
>(content.size()));
142 fs::rename(tmp, agg_path, ec);
143 if (ec) fs::remove(tmp, ec);
144 return {raw.size(), latest.size()};
156inline std::vector<std::pair<int, std::string>>
collect(
const std::string& pe_dir) {
157 std::vector<std::pair<int, std::string>> raw;
159 if (!fs::exists(pe_dir, ec))
return {};
160 for (
auto& entry : fs::recursive_directory_iterator(pe_dir, ec)) {
162 if (!entry.is_regular_file())
continue;
163 const std::string fname = entry.path().filename().string();
166 }
else if (fname.size() > 7 && fname.compare(0, 7,
"ZPENode") == 0
167 && fname.back() ==
't') {
168 const size_t us = fname.find(
'_'), dot = fname.find(
'.');
169 if (us == std::string::npos || dot == std::string::npos || dot <= us)
continue;
171 try {
id = std::stoi(fname.substr(us + 1, dot - us - 1)); }
172 catch (...) {
continue; }
173 std::ifstream fin(entry.path());
174 std::string content((std::istreambuf_iterator<char>(fin)),
175 std::istreambuf_iterator<char>());
176 raw.emplace_back(
id, std::move(content));
179 std::map<int, std::string> latest;
180 for (
auto& [
id, content] : raw) {
181 if (
id < 0)
continue;
182 latest[id] = std::move(content);
184 return {latest.begin(), latest.end()};
200 std::vector<std::pair<int, std::string>> entries,
202 std::sort(entries.begin(), entries.end(),
203 [](
const auto& a,
const auto& b) { return a.first < b.first; });
205 fs::remove_all(pe_dir, ec);
206 const std::string folder = pe_dir +
"PEFolder_0/";
207 fs::create_directories(folder, ec);
210 for (
size_t i = 0; i < entries.size(); ++i) {
211 fout <<
"#PE " << i <<
' ' << entries[i].second.size() <<
'\n';
212 fout.write(entries[i].second.data(),
213 static_cast<std::streamsize
>(entries[i].second.size()));
217 for (
size_t i = 0; i < entries.size(); ++i) {
218 std::ofstream fout(folder +
"ZPENode_" + std::to_string(i) +
".txt");
219 fout << entries[i].second;
222 return entries.size();
256 if (!fs::exists(pe_dir, ec))
return 0;
260 const std::string journal_path = pe_dir +
"/renumber.map";
261 const std::string folder = (fs::path(pe_dir) /
"PEFolder_0").
string() +
"/";
262 std::vector<std::pair<int, int>> mapping;
264 std::ifstream jin(journal_path);
268 std::getline(jin, header);
270 while (jin >> o >> n) mapping.emplace_back(o, n);
271 if (header.rfind(
"# adsidac pe renumber v1", 0) != 0 || mapping.empty())
276 std::map<int, fs::path> ids;
277 for (
auto& entry : fs::recursive_directory_iterator(pe_dir, ec)) {
279 if (!entry.is_regular_file())
continue;
280 const std::string fname = entry.path().filename().string();
283 if (fname.size() > 7 && fname.compare(0, 7,
"ZPENode") == 0
284 && fname.back() ==
't') {
285 const size_t us = fname.find(
'_'), dot = fname.find(
'.');
286 if (us == std::string::npos || dot == std::string::npos || dot <= us)
continue;
288 try {
id = std::stoi(fname.substr(us + 1, dot - us - 1)); }
289 catch (...) {
continue; }
290 if (
id < 0)
continue;
291 if (!ids.emplace(
id, entry.path()).second)
295 if (ids.empty())
return 0;
297 bool done = ids.rbegin()->first ==
static_cast<int>(ids.size()) - 1;
299 for (
auto& [
id, p] : ids)
300 if (p.parent_path().filename() !=
"PEFolder_0") { done =
false;
break; }
303 for (
auto& [
id, p] : ids) mapping.emplace_back(
id, next++);
304 std::ofstream jout(journal_path, std::ios::trunc);
305 jout <<
"# adsidac pe renumber v1 " << mapping.size() <<
'\n';
306 for (
auto& [o, n] : mapping) jout << o <<
' ' << n <<
'\n';
312 if (!mapping.empty()) {
313 fs::create_directories(folder, ec);
316 for (
auto& [oldid, newid] : mapping) {
317 const std::string final_name = folder +
"ZPENode_" + std::to_string(newid) +
".txt";
318 const std::string tmp_name = folder +
"tmp_" + std::to_string(newid);
319 if (fs::exists(final_name, ec) || fs::exists(tmp_name, ec))
continue;
320 const std::string old_name = (fs::path(pe_dir) / (
"PEFolder_" + std::to_string(oldid / 1000))
321 / (
"ZPENode_" + std::to_string(oldid) +
".txt")).string();
322 if (fs::exists(old_name, ec)) {
323 fs::rename(old_name, tmp_name, ec);
327 for (
auto& entry : fs::recursive_directory_iterator(pe_dir, ec)) {
328 if (!entry.is_regular_file())
continue;
329 if (entry.path().filename() ==
"ZPENode_" + std::to_string(oldid) +
".txt") {
330 fs::rename(entry.path(), tmp_name, ec);
337 for (
auto& [oldid, newid] : mapping) {
338 const std::string tmp_name = folder +
"tmp_" + std::to_string(newid);
339 if (fs::exists(tmp_name, ec))
340 fs::rename(tmp_name, folder +
"ZPENode_" + std::to_string(newid) +
".txt", ec);
348 std::vector<fs::path> doomed;
349 for (
auto& entry : fs::recursive_directory_iterator(pe_dir, ec)) {
350 if (!entry.is_regular_file())
continue;
351 const std::string fname = entry.path().filename().string();
352 if (fname.size() > 8 && fname.compare(0, 8,
"ZPENode_") == 0 && fname[8] ==
'-')
353 doomed.push_back(entry.path());
354 else if (fname.compare(0, 7,
"ZPENode") == 0 && fname.back() ==
't')
357 for (
auto& p : doomed) fs::remove(p, ec);
358 for (
auto& entry : fs::directory_iterator(pe_dir, ec)) {
359 if (entry.is_directory() && entry.path().filename() !=
"PEFolder_0"
360 && fs::is_empty(entry.path(), ec))
361 fs::remove(entry.path(), ec);
363 fs::remove(journal_path, ec);
void parse_aggregate(const fs::path &path, std::vector< std::pair< int, std::string > > &out)
Parse one aggregate file, appending (id, content) to out in file order, duplicates and negative ids i...
std::vector< std::pair< int, std::string > > collect(const std::string &pe_dir)
Collect every PE node under pe_dir (recursively), from either layout, reading all node content into m...
void append_record(const std::string &pe_dir, int branch_id, const std::string &content)
Append one node record to <pe_dir>ZPENodes_agg.txt.
size_t rewrite_sequential(const std::string &pe_dir, std::vector< std::pair< int, std::string > > entries, bool aggregate)
Replace the contents of pe_dir with entries renumbered 0..N-1 in ascending id order (the content path...
const char * aggregate_basename()
Basename of the aggregate file ("ZPENodes_agg.txt"). It is in the MPI merge's append-files list,...
std::pair< size_t, size_t > compact_aggregate(const fs::path &agg_path)
Rewrite one rank's aggregate file last-wins per id, sorted by id.
size_t finalize_sequential(const std::string &pe_dir, bool aggregate)
End-of-run finalize: renumber every PE node 0..N-1 in id order, ending in the same layout rewrite_seq...