Skip to content

Commit

Permalink
init: Take lock on blocks directory in BlockManager ctor
Browse files Browse the repository at this point in the history
This moves the responsibility of taking the lock for the blocks
directory into the BlockManager. An RAII wrapper is introduced for it to
ensure it is the first resource to be acquired and is released again
after use.

This is relevant for the kernel library where the lock should be taken
even if the user fails to explicitly do so.
  • Loading branch information
TheCharlatan committed Feb 13, 2025
1 parent 104593d commit 436df34
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 6 deletions.
5 changes: 3 additions & 2 deletions src/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1109,8 +1109,9 @@ static bool LockDirectory(const fs::path& dir, bool probeOnly)
}
static bool LockDirectories(bool probeOnly)
{
return LockDirectory(gArgs.GetDataDirNet(), probeOnly) && \
LockDirectory(gArgs.GetBlocksDirPath(), probeOnly);
// Only allow probing the blocks directory, the BlockManager takes the lock internally.
return LockDirectory(gArgs.GetDataDirNet(), probeOnly) &&
(probeOnly ? LockDirectory(gArgs.GetBlocksDirPath(), probeOnly) : true);
}

bool AppInitSanityChecks(const kernel::Context& kernel)
Expand Down
7 changes: 4 additions & 3 deletions src/init/common.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,9 +117,10 @@ bool StartLogging(const ArgsManager& args)
}

if (!LogInstance().m_log_timestamps)
LogPrintf("Startup time: %s\n", FormatISO8601DateTime(GetTime()));
LogPrintf("Default data directory %s\n", fs::PathToString(GetDefaultDataDir()));
LogPrintf("Using data directory %s\n", fs::PathToString(gArgs.GetDataDirNet()));
LogInfo("Startup time: %s", FormatISO8601DateTime(GetTime()));
LogInfo("Default data directory %s", fs::PathToString(GetDefaultDataDir()));
LogInfo("Using data directory %s", fs::PathToString(gArgs.GetDataDirNet()));
LogInfo("Using blocks directory %s", fs::PathToString(gArgs.GetBlocksDirPath()));

// Only log conf file usage message if conf file actually exists.
fs::path config_file_path = args.GetConfigFilePath();
Expand Down
26 changes: 25 additions & 1 deletion src/node/blockstorage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

#include <node/blockstorage.h>

#include <bitcoin-build-config.h> // IWYU pragma: keep

#include <arith_uint256.h>
#include <chain.h>
#include <consensus/params.h>
Expand Down Expand Up @@ -31,6 +33,7 @@
#include <util/batchpriority.h>
#include <util/check.h>
#include <util/fs.h>
#include <util/fs_helpers.h>
#include <util/signalinterrupt.h>
#include <util/strencodings.h>
#include <util/translation.h>
Expand Down Expand Up @@ -1164,8 +1167,29 @@ static auto InitBlocksdirXorKey(const BlockManager::Options& opts)
return std::vector<std::byte>{xor_key.begin(), xor_key.end()};
}

BlockDirLock::BlockDirLock(const fs::path& blocks_dir)
: m_path{blocks_dir}
{
// Make sure only a single BlockManager is using the blocks directory.
switch (util::LockDirectory(blocks_dir, ".lock", false)) {
case util::LockResult::ErrorWrite:
throw std::runtime_error(strprintf(_("Cannot write to block directory '%s'; check permissions."), fs::PathToString(blocks_dir)).original);
case util::LockResult::ErrorLock:
throw std::runtime_error(strprintf(_("Cannot obtain a lock on block directory %s. %s is probably already running."), fs::PathToString(blocks_dir), CLIENT_NAME).original);
case util::LockResult::Success:
return;
} // no default case, so the compiler can warn about missing cases
assert(false);
}

BlockDirLock::~BlockDirLock()
{
UnlockDirectory(m_path, ".lock");
}

BlockManager::BlockManager(const util::SignalInterrupt& interrupt, Options opts)
: m_prune_mode{opts.prune_target > 0},
: m_lock{BlockDirLock(opts.blocks_dir)},
m_prune_mode{opts.prune_target > 0},
m_xor_key{InitBlocksdirXorKey(opts)},
m_opts{std::move(opts)},
m_block_file_seq{FlatFileSeq{m_opts.blocks_dir, "blk", m_opts.fast_prune ? 0x4000 /* 16kB */ : BLOCKFILE_CHUNK_SIZE}},
Expand Down
9 changes: 9 additions & 0 deletions src/node/blockstorage.h
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,14 @@ struct BlockfileCursor {

std::ostream& operator<<(std::ostream& os, const BlockfileCursor& cursor);

class BlockDirLock
{
fs::path m_path;

public:
explicit BlockDirLock(const fs::path& blocks_dir);
~BlockDirLock();
};

/**
* Maintains a tree of blocks (stored in `m_block_index`) which is consulted
Expand All @@ -141,6 +149,7 @@ class BlockManager
friend ChainstateManager;

private:
BlockDirLock m_lock;
const CChainParams& GetParams() const { return m_opts.chainparams; }
const Consensus::Params& GetConsensus() const { return m_opts.chainparams.GetConsensus(); }
/**
Expand Down

0 comments on commit 436df34

Please sign in to comment.