upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/rpc.cpp38
1 files changed, 28 insertions, 10 deletions
diff --git a/src/rpc.cpp b/src/rpc.cpp
index f853e78..be265db 100644
--- a/src/rpc.cpp
+++ b/src/rpc.cpp
@@ -506,20 +506,35 @@ static void SyncDirectoryOf(const std::string& path)
506// write mutex for `path`: the temp name is derived from the target, so two 506// write mutex for `path`: the temp name is derived from the target, so two
507// threads in here at once for one path is precisely the race this exists to 507// threads in here at once for one path is precisely the race this exists to
508// prevent. 508// prevent.
509//
510// Every failure removes the temp file before returning. It used to be left
511// where it fell, so a disk that filled up once left a short, valid-looking
512// "pending_payouts.json.tmp" next to the good ledger for as long as the node
513// ran. That file is a trap: it has the name of a half-finished save, and an
514// operator cleaning up after an incident is exactly the person who will move
515// it into place.
516//
517// Failures print unconditionally rather than through LogPrint(). These three
518// files are written under two different debug categories ("payout" for the
519// ledgers, "pool" for the status file), and a write failure is not a trace of
520// normal operation -- it is the file the operator is about to read not being
521// there. Gating it behind a category that had to be chosen before the failure
522// happened is how "could not replace pool_status.json" went missing.
509static bool WriteFileAtomic(const std::string& path, const std::string& data, 523static bool WriteFileAtomic(const std::string& path, const std::string& data,
510 const char* what) 524 const char* what)
511{ 525{
512 std::string tmp = path + ".tmp"; 526 std::string tmp = path + ".tmp";
513 FILE* f = fopen(tmp.c_str(), "w"); 527 FILE* f = fopen(tmp.c_str(), "w");
514 if (!f) { 528 if (!f) {
515 LogPrint("payout", "[payout] WARNING: could not write %s (%s)\n", 529 printf("[payout] WARNING: could not write %s (%s)\n",
516 tmp.c_str(), what); 530 tmp.c_str(), what);
517 return false; 531 return false;
518 } 532 }
519 if (!data.empty() && fwrite(data.c_str(), 1, data.size(), f) != data.size()) { 533 if (!data.empty() && fwrite(data.c_str(), 1, data.size(), f) != data.size()) {
520 LogPrint("payout", "[payout] WARNING: short write to %s (%s)\n", 534 printf("[payout] WARNING: short write to %s (%s)\n",
521 tmp.c_str(), what); 535 tmp.c_str(), what);
522 fclose(f); 536 fclose(f);
537 remove(tmp.c_str());
523 return false; 538 return false;
524 } 539 }
525 // Before the rename, not after: publishing a name that points at nothing 540 // Before the rename, not after: publishing a name that points at nothing
@@ -527,9 +542,10 @@ static bool WriteFileAtomic(const std::string& path, const std::string& data,
527 // made durable, do not rename -- the previous file is still intact and 542 // made durable, do not rename -- the previous file is still intact and
528 // still correct, and the next write will try again. 543 // still correct, and the next write will try again.
529 if (!SyncFileHandle(f)) { 544 if (!SyncFileHandle(f)) {
530 LogPrint("payout", "[payout] WARNING: could not flush %s to disk (%s)" 545 printf("[payout] WARNING: could not flush %s to disk (%s)"
531 " -- keeping the previous file\n", tmp.c_str(), what); 546 " -- keeping the previous file\n", tmp.c_str(), what);
532 fclose(f); 547 fclose(f);
548 remove(tmp.c_str());
533 return false; 549 return false;
534 } 550 }
535 // fclose() is where buffered data actually reaches the OS, so a failure 551 // fclose() is where buffered data actually reaches the OS, so a failure
@@ -537,8 +553,9 @@ static bool WriteFileAtomic(const std::string& path, const std::string& data,
537 // destroy the good copy, which is exactly what these files exist to 553 // destroy the good copy, which is exactly what these files exist to
538 // prevent. 554 // prevent.
539 if (fclose(f) != 0) { 555 if (fclose(f) != 0) {
540 LogPrint("payout", "[payout] WARNING: could not close %s (%s)\n", 556 printf("[payout] WARNING: could not close %s (%s)\n",
541 tmp.c_str(), what); 557 tmp.c_str(), what);
558 remove(tmp.c_str());
542 return false; 559 return false;
543 } 560 }
544#ifdef _WIN32 561#ifdef _WIN32
@@ -546,8 +563,9 @@ static bool WriteFileAtomic(const std::string& path, const std::string& data,
546 remove(path.c_str()); 563 remove(path.c_str());
547#endif 564#endif
548 if (rename(tmp.c_str(), path.c_str()) != 0) { 565 if (rename(tmp.c_str(), path.c_str()) != 0) {
549 LogPrint("payout", "[payout] WARNING: could not replace %s (%s)\n", 566 printf("[payout] WARNING: could not replace %s (%s)\n",
550 path.c_str(), what); 567 path.c_str(), what);
568 remove(tmp.c_str());
551 return false; 569 return false;
552 } 570 }
553 SyncDirectoryOf(path); 571 SyncDirectoryOf(path);