diff --git a/include/bitcoin/database/impl/store.ipp b/include/bitcoin/database/impl/store.ipp index 676c45eb..0310a5ee 100644 --- a/include/bitcoin/database/impl/store.ipp +++ b/include/bitcoin/database/impl/store.ipp @@ -904,29 +904,40 @@ code CLASS::backup(const event_handler& handler, bool prune) NOEXCEPT static const auto primary = configuration_.path / schema::dir::primary; static const auto secondary = configuration_.path / schema::dir::secondary; + static const auto temporary = configuration_.path / schema::dir::temporary; handler(event_t::archive_snapshot, table_t::store); + // Ensure existing and empty /temporary. + if ((ec = file::clear_directory_ex(temporary))) return ec; + + // Ensure no /primary. if (file::is_directory(primary)) { - // Delete /secondary, rename /primary to /secondary. + // Delete /secondary. if ((ec = file::clear_directory_ex(secondary))) return ec; if ((ec = file::remove_ex(secondary))) return ec; + + // Rename /primary to /secondary (atomic). if ((ec = file::rename_ex(primary, secondary))) return ec; } - // Dump /heads memory maps to /primary. - if ((ec = file::clear_directory_ex(primary))) return ec; - ec = dump(primary, handler); + // Dump /heads memory maps to /temporary. + if ((ec = dump(temporary, handler))) + { + // Failed dump, clear temporary and rename secondary to primary. + if (file::clear_directory(temporary) && file::remove(temporary)) + file::rename(secondary, primary); - // If failed clear primary and rename secondary to primary. - if (ec && file::clear_directory(primary) && file::remove(primary)) - /* bool */ file::rename(secondary, primary); + // Return original fault. + return ec; + } - return ec; + // Rename /temporary to /primary (atomic). + return file::rename_ex(temporary, primary); } -// Dump memory maps of /heads to new files in /primary. +// Dump memory maps of /heads to new files in /temporary. // Heads are copied from RAM, not flushed to disk and copied as files. TEMPLATE code CLASS::dump(const path& folder, @@ -1037,9 +1048,14 @@ code CLASS::restore(const event_handler& handler) NOEXCEPT static const auto heads = configuration_.path / schema::dir::heads; static const auto primary = configuration_.path / schema::dir::primary; static const auto secondary = configuration_.path / schema::dir::secondary; + static const auto temporary = configuration_.path / schema::dir::temporary; handler(event_t::recover_snapshot, table_t::store); + // Clean up any residual /temporary. + file::clear_directory(temporary); + file::remove(temporary); + if (file::is_directory(primary)) { // Clear invalid /heads, recover from /primary, clone to /primary. @@ -1047,7 +1063,6 @@ code CLASS::restore(const event_handler& handler) NOEXCEPT if (!ec) ec = file::remove_ex(heads); if (!ec) ec = file::rename_ex(primary, heads); if (!ec) ec = file::copy_directory_ex(heads, primary); - if (ec) /* bool */ file::remove_ex(primary); } else if (file::is_directory(secondary)) { @@ -1056,7 +1071,6 @@ code CLASS::restore(const event_handler& handler) NOEXCEPT if (!ec) ec = file::remove_ex(heads); if (!ec) ec = file::rename_ex(secondary, heads); if (!ec) ec = file::copy_directory_ex(heads, primary); - if (ec) /* bool */ file::remove_ex(secondary); } else { diff --git a/include/bitcoin/database/tables/names.hpp b/include/bitcoin/database/tables/names.hpp index d9b096df..f3d6ddef 100644 --- a/include/bitcoin/database/tables/names.hpp +++ b/include/bitcoin/database/tables/names.hpp @@ -31,6 +31,7 @@ namespace dir constexpr auto heads = "heads"; constexpr auto primary = "primary"; constexpr auto secondary = "secondary"; + constexpr auto temporary = "temporary"; } namespace archive