Skip to content

Commit 71d67c7

Browse files
authored
Merge pull request libbitcoin#664 from evoskuil/master
Make backup write fully atomic.
2 parents 54875d4 + cea12a3 commit 71d67c7

File tree

2 files changed

+26
-11
lines changed

2 files changed

+26
-11
lines changed

include/bitcoin/database/impl/store.ipp

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -904,29 +904,40 @@ code CLASS::backup(const event_handler& handler, bool prune) NOEXCEPT
904904

905905
static const auto primary = configuration_.path / schema::dir::primary;
906906
static const auto secondary = configuration_.path / schema::dir::secondary;
907+
static const auto temporary = configuration_.path / schema::dir::temporary;
907908

908909
handler(event_t::archive_snapshot, table_t::store);
909910

911+
// Ensure existing and empty /temporary.
912+
if ((ec = file::clear_directory_ex(temporary))) return ec;
913+
914+
// Ensure no /primary.
910915
if (file::is_directory(primary))
911916
{
912-
// Delete /secondary, rename /primary to /secondary.
917+
// Delete /secondary.
913918
if ((ec = file::clear_directory_ex(secondary))) return ec;
914919
if ((ec = file::remove_ex(secondary))) return ec;
920+
921+
// Rename /primary to /secondary (atomic).
915922
if ((ec = file::rename_ex(primary, secondary))) return ec;
916923
}
917924

918-
// Dump /heads memory maps to /primary.
919-
if ((ec = file::clear_directory_ex(primary))) return ec;
920-
ec = dump(primary, handler);
925+
// Dump /heads memory maps to /temporary.
926+
if ((ec = dump(temporary, handler)))
927+
{
928+
// Failed dump, clear temporary and rename secondary to primary.
929+
if (file::clear_directory(temporary) && file::remove(temporary))
930+
file::rename(secondary, primary);
921931

922-
// If failed clear primary and rename secondary to primary.
923-
if (ec && file::clear_directory(primary) && file::remove(primary))
924-
/* bool */ file::rename(secondary, primary);
932+
// Return original fault.
933+
return ec;
934+
}
925935

926-
return ec;
936+
// Rename /temporary to /primary (atomic).
937+
return file::rename_ex(temporary, primary);
927938
}
928939

929-
// Dump memory maps of /heads to new files in /primary.
940+
// Dump memory maps of /heads to new files in /temporary.
930941
// Heads are copied from RAM, not flushed to disk and copied as files.
931942
TEMPLATE
932943
code CLASS::dump(const path& folder,
@@ -1037,17 +1048,21 @@ code CLASS::restore(const event_handler& handler) NOEXCEPT
10371048
static const auto heads = configuration_.path / schema::dir::heads;
10381049
static const auto primary = configuration_.path / schema::dir::primary;
10391050
static const auto secondary = configuration_.path / schema::dir::secondary;
1051+
static const auto temporary = configuration_.path / schema::dir::temporary;
10401052

10411053
handler(event_t::recover_snapshot, table_t::store);
10421054

1055+
// Clean up any residual /temporary.
1056+
file::clear_directory(temporary);
1057+
file::remove(temporary);
1058+
10431059
if (file::is_directory(primary))
10441060
{
10451061
// Clear invalid /heads, recover from /primary, clone to /primary.
10461062
ec = file::clear_directory_ex(heads);
10471063
if (!ec) ec = file::remove_ex(heads);
10481064
if (!ec) ec = file::rename_ex(primary, heads);
10491065
if (!ec) ec = file::copy_directory_ex(heads, primary);
1050-
if (ec) /* bool */ file::remove_ex(primary);
10511066
}
10521067
else if (file::is_directory(secondary))
10531068
{
@@ -1056,7 +1071,6 @@ code CLASS::restore(const event_handler& handler) NOEXCEPT
10561071
if (!ec) ec = file::remove_ex(heads);
10571072
if (!ec) ec = file::rename_ex(secondary, heads);
10581073
if (!ec) ec = file::copy_directory_ex(heads, primary);
1059-
if (ec) /* bool */ file::remove_ex(secondary);
10601074
}
10611075
else
10621076
{

include/bitcoin/database/tables/names.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ namespace dir
3131
constexpr auto heads = "heads";
3232
constexpr auto primary = "primary";
3333
constexpr auto secondary = "secondary";
34+
constexpr auto temporary = "temporary";
3435
}
3536

3637
namespace archive

0 commit comments

Comments
 (0)