Skip to content

Commit

Permalink
Add read-only mode, do not allow inserts
Browse files Browse the repository at this point in the history
  • Loading branch information
movitto committed Jun 19, 2019
1 parent 37ee4fd commit 4b8c2bf
Show file tree
Hide file tree
Showing 2 changed files with 157 additions and 0 deletions.
43 changes: 43 additions & 0 deletions include/nudb/basic_store.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,14 @@ class basic_store
path_type const& dp_, path_type const& kp_,
path_type const& lp_,
detail::key_file_header const& kh_);

state(File&& df_, File&& kf_,
path_type const& dp_, path_type const& kp_,
detail::key_file_header const& kh_);
};

bool open_ = false;
bool read_only_ = false;

// Use optional because some
// members cannot be default-constructed.
Expand Down Expand Up @@ -173,6 +178,19 @@ class basic_store
return open_;
}

/** Returns `true` if the database is read only.
@par Thread safety
Safe to call concurrently with any function
except @ref open.
*/
bool
is_read_only() const
{
return read_only_;
}

/** Return the path to the data file.
@par Requirements
Expand Down Expand Up @@ -373,6 +391,31 @@ class basic_store
error_code& ec,
Args&&... args);

/** Open a database in read only mode.
Takes same parameters as open but opens
all files in read mode and disallows
insertions.
*/
template<class... Args>
void
open_read_only(
path_type const& dat_path,
path_type const& key_path,
error_code& ec,
Args&&... args);

/** Open a database directory in read only mode.
*/
template<class... Args>
void
open_read_only(
path_type const& dir_path,
error_code& ec,
Args&&... args);

/** Fetch a value.
The function checks the database for the specified
Expand Down
114 changes: 114 additions & 0 deletions include/nudb/impl/basic_store.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,26 @@ state(File&& df_, File&& kf_, File&& lf_,
"File requirements not met");
}

template<class Hasher, class File>
basic_store<Hasher, File>::state::
state(File&& df_, File&& kf_,
path_type const& dp_, path_type const& kp_,
detail::key_file_header const& kh_)
: df(std::move(df_))
, kf(std::move(kf_))
, dp(dp_)
, kp(kp_)
, hasher(kh_.salt)
, p0(kh_.key_size, "p0")
, p1(kh_.key_size, "p1")
, c1(kh_.key_size, kh_.block_size, "c1")
, kh(kh_)
{
static_assert(is_File<File>::value,
"File requirements not met");
}


//------------------------------------------------------------------------------

template<class Hasher, class File>
Expand Down Expand Up @@ -214,6 +234,92 @@ open(
ec, args...);
}

template<class Hasher, class File>
template<class... Args>
void
basic_store<Hasher, File>::
open_read_only(
path_type const& dat_path,
path_type const& key_path,
error_code& ec,
Args&&... args)
{
static_assert(is_Hasher<Hasher>::value,
"Hasher requirements not met");
using namespace detail;
BOOST_ASSERT(! is_open());
ec_ = {};
ecb_.store(false);

File df(args...);
File kf(args...);
df.open(file_mode::read, dat_path, ec);
if(ec)
return;
kf.open(file_mode::read, key_path, ec);
if(ec)
return;

dat_file_header dh;
read(df, dh, ec);
if(ec)
return;
verify(dh, ec);
if(ec)
return;

key_file_header kh;
read(kf, kh, ec);
if(ec)
return;
verify<Hasher>(kh, ec);
if(ec)
return;

verify<Hasher>(dh, kh, ec);
if(ec)
return;

boost::optional<state> s;
s.emplace(std::move(df), std::move(kf),
dat_path, key_path, kh);
thresh_ = std::max<std::size_t>(65536UL,
kh.load_factor * kh.capacity);
frac_ = thresh_ / 2;
buckets_ = kh.buckets;
modulus_ = ceil_pow2(kh.buckets);
// VFALCO TODO This could be better
if(buckets_ < 1)
{
ec = error::short_key_file;
return;
}
s_.emplace(std::move(*s));
open_ = true;
read_only_ = true;
ctx_->insert(*this);
}

template<class Hasher, class File>
template<class... Args>
void
basic_store<Hasher, File>::
open_read_only(
path_type const& dir_path,
error_code& ec,
Args&&... args){
BOOST_ASSERT(boost::filesystem::exists(dir_path));

boost::filesystem::path fs_dir_path(dir_path);

boost::filesystem::path dat_path =
fs_dir_path / detail::default_dat_file();
boost::filesystem::path key_path =
fs_dir_path / detail::default_key_file();

open_read_only(dat_path.string(), key_path.string(), ec, args...);
}

template<class Hasher, class File>
void
basic_store<Hasher, File>::
Expand All @@ -223,6 +329,10 @@ close(error_code& ec)
{
open_ = false;
ctx_->erase(*this);

if(read_only_)
return;

if(! s_->p1.empty())
{
std::size_t work;
Expand Down Expand Up @@ -302,6 +412,7 @@ insert(
using namespace detail;
using namespace std::chrono;
BOOST_ASSERT(is_open());
BOOST_ASSERT(!is_read_only());
if(ecb_)
{
ec = ec_;
Expand Down Expand Up @@ -776,6 +887,9 @@ flush()
using namespace std::chrono;
using namespace detail;

if(is_read_only())
return;

#if NUDB_DEBUG_LOG
beast::unit_test::dstream dout{std::cout};
#endif
Expand Down

0 comments on commit 4b8c2bf

Please sign in to comment.