ircd::db: Simplify options wrappings; eliminate bitflags.

This commit is contained in:
Jason Volk 2022-07-02 11:37:49 -07:00
parent 4e7f5af457
commit 94a6cd0d90
9 changed files with 107 additions and 185 deletions

View File

@ -46,8 +46,6 @@ struct ircd::db::domain
using iterator_type = const_iterator;
using const_iterator_type = const_iterator;
static const gopts applied_opts;
const_iterator end(const string_view &key, gopts = {});
const_iterator begin(const string_view &key, gopts = {});
const_reverse_iterator rend(const string_view &key, gopts = {});

View File

@ -13,82 +13,72 @@
namespace ircd::db
{
enum class set :uint64_t;
enum class get :uint64_t;
struct options;
template<class> struct opts;
struct sopts;
struct gopts;
template<class T> bool test(const opts<T> &, const typename std::underlying_type<T>::type &);
template<class T> bool test(const opts<T> &, const T &value);
template<class T> opts<T> &operator|=(opts<T> &, const opts<T> &);
template<class T> opts<T> &operator|=(opts<T> &, const T &value);
template<class T> opts<T> &operator&=(opts<T> &, const opts<T> &);
template<class T> opts<T> &operator&=(opts<T> &, const T &value);
struct options;
}
enum class ircd::db::set
:uint64_t
{
FSYNC = 0x0001, ///< Uses kernel filesystem synchronization after write (slow).
NO_JOURNAL = 0x0002, ///< Write Ahead Log (WAL) for some crash recovery (danger).
NO_BLOCKING = 0x0004, ///< Fail if write would block.
NO_COLUMN_ERR = 0x0008, ///< No exception thrown when writing to a deleted column.
PRIO_LOW = 0x0010, ///< Mark for low priority behavior.
PRIO_HIGH = 0x0020, ///< Mark for high priority behavior.
};
enum class ircd::db::get
:uint64_t
{
PIN = 0x0001, ///< Keep iter data in memory for iter lifetime (good for lots ++/--).
PREFIX = 0x0002, ///< (prefix_same_as_start); automatic for index columns with pfx.
ORDERED = 0x0004, ///< (total_order_seek); relevant to index columns.
CACHE = 0x0008, ///< Update the cache.
NO_CACHE = 0x0010, ///< Do not update the cache.
CHECKSUM = 0x0020, ///< Integrity of data will be checked (overrides conf).
NO_CHECKSUM = 0x0040, ///< Integrity of data will not be checked (overrides conf).
NO_BLOCKING = 0x0080, ///< Fail if read would block from not being cached.
NO_SNAPSHOT = 0x0100, ///< This iterator will have the latest data (tailing).
NO_PARALLEL = 0x0200, ///< Don't submit requests in parallel (relevant to db::row).
THROW = 0x0400, ///< Throw exceptions more than usual.
NO_THROW = 0x0800, ///< Suppress exceptions if possible.
};
template<class T>
struct ircd::db::opts
{
using flag_t = typename std::underlying_type<T>::type;
flag_t value {0};
opts() = default;
opts(const std::initializer_list<T> &list)
:value{combine_flags(list)}
{}
};
/// options for writing (set)
/// Options for setting (writes)
struct ircd::db::sopts
:opts<set>
{
using opts<set>::opts;
/// Uses kernel filesystem synchronization after this write (slow).
bool fsync {false};
/// Write Ahead Log (WAL) for some crash recovery.
bool journal {true};
/// Set to false to fail if write would block.
bool blocking {true};
/// Mark for low priority behavior.
bool prio_low {false};
/// Mark for high priority behavior.
bool prio_high {false};
};
/// options for reading (get)
/// Options for getting (reads)
struct ircd::db::gopts
:opts<get>
{
database::snapshot snapshot;
const rocksdb::Slice *lower_bound { nullptr };
const rocksdb::Slice *upper_bound { nullptr };
size_t readahead { 0 };
/// Keep iter data in memory for iter lifetime (good for lots ++/--).
bool pin {false};
using opts<get>::opts;
/// Fill the cache with results.
bool cache {true};
/// Allow query to continue after cache miss.
bool blocking {true};
/// Submit requests in parallel (relevant to db::row).
bool parallel {true};
/// (prefix_same_as_start); automatic for index columns with pfx.
bool prefix {false};
/// (total_order_seek); relevant to index columns.
bool ordered {false};
/// Ensures no snapshot is used; this iterator will have the latest data.
bool tailing {false};
/// 1 = Throw exceptions more than usual.
/// 0 = Throw exceptions less than usual.
int8_t throwing {-1};
/// 1 = Integrity of data will be checked (overrides conf).
/// 0 = Checksums will not be checked (overrides conf).
int8_t checksum {-1};
/// Readahead bytes.
size_t readahead {0};
/// Bounding keys
const rocksdb::Slice
*lower_bound {nullptr},
*upper_bound {nullptr};
/// Attached snapshot
database::snapshot snapshot;
};
/// options <-> string
@ -134,63 +124,3 @@ struct ircd::db::options::map
:std::unordered_map<std::string, std::string>{std::move(m)}
{}
};
template<class T>
inline ircd::db::opts<T> &
ircd::db::operator&=(opts<T> &a,
const T &value)
{
using flag_t = typename opts<T>::flag_t;
a.value &= flag_t(value);
return a;
}
template<class T>
inline ircd::db::opts<T> &
ircd::db::operator&=(opts<T> &a,
const opts<T> &b)
{
a.value &= b.value;
return a;
}
template<class T>
inline ircd::db::opts<T> &
ircd::db::operator|=(opts<T> &a,
const T &value)
{
using flag_t = typename opts<T>::flag_t;
a.value |= flag_t(value);
return a;
}
template<class T>
inline ircd::db::opts<T> &
ircd::db::operator|=(opts<T> &a,
const opts<T> &b)
{
a.value |= b.value;
return a;
}
template<class T>
inline bool
ircd::db::test(const opts<T> &a,
const T &value)
{
using flag_t = typename opts<T>::flag_t;
return a.value & flag_t(value);
}
template<class T>
inline bool
ircd::db::test(const opts<T> &a,
const typename std::underlying_type<T>::type &value)
{
using flag_t = typename opts<T>::flag_t;
return a.value & flag_t(value);
}

View File

@ -72,7 +72,7 @@ struct ircd::m::dbs::write_opts
db::op op {db::op::SET};
/// Lower-level write options passed to the transaction's execution.
db::sopts sopts {(db::set)0};
db::sopts sopts;
/// Principal's index number. Most codepaths do not permit zero. This may
/// be zero for blacklisting, but the blacklist option must be set.

View File

@ -614,7 +614,7 @@ ircd::db::prefetcher::operator()(column &c,
// control queue growth, so we insert voluntary yield here to allow
// prefetch operations to at least be processed before returning to
// the user submitting more prefetches.
if(likely(!test(opts, db::get::NO_BLOCKING)))
if(likely(opts.blocking))
ctx::yield();
return true;
@ -1725,15 +1725,15 @@ ircd::db::seek(row &r,
{
// If there's a pending error from another cell by the time this
// closure is executed we don't perform the seek() unless the user
// specifies db::get::NO_THROW to suppress it.
if(!eptr || test(opts, get::NO_THROW)) try
// specifies db::gopts::throwing=0 to suppress it.
if(!eptr || opts.throwing == false) try
{
if(!seek(cell, key))
{
// If the cell is not_found that's not a thrown exception here;
// the cell will just be !valid(). The user can specify
// get::THROW to propagate a not_found from the seek(row);
if(test(opts, get::THROW))
// the cell will just be !valid(). The user can option
// throwing=1 to propagate a not_found from the seek(row).
if(opts.throwing == true)
throw not_found
{
"column '%s' key '%s'", cell.col(), key
@ -1787,7 +1787,7 @@ ircd::db::seek(row &r,
const bool submit
{
r.size() > 1 &&
!test(opts, get::NO_PARALLEL) &&
opts.parallel &&
!db::cached(column, key, opts)
};
@ -1824,7 +1824,7 @@ ircd::db::seek(row &r,
};
}
if(eptr && !test(opts, get::NO_THROW))
if(eptr && opts.throwing != false)
std::rethrow_exception(eptr);
return ret;
@ -2346,12 +2346,6 @@ const
// db/domain.h
//
const ircd::db::gopts
ircd::db::domain::applied_opts
{
get::PREFIX
};
bool
ircd::db::seek(domain::const_iterator_base &it,
const pos &p)
@ -2373,7 +2367,7 @@ ircd::db::seek(domain::const_iterator_base &it,
break;
}
it.opts |= domain::applied_opts;
it.opts.prefix = true;
return seek(static_cast<column::const_iterator_base &>(it), p);
}
@ -2381,7 +2375,7 @@ bool
ircd::db::seek(domain::const_iterator_base &it,
const string_view &p)
{
it.opts |= domain::applied_opts;
it.opts.prefix = true;
return seek(static_cast<column::const_iterator_base &>(it), p);
}
@ -5277,29 +5271,26 @@ ircd::db::make_opts(const gopts &opts)
ret.iterate_lower_bound = opts.lower_bound;
ret.iterate_upper_bound = opts.upper_bound;
ret.verify_checksums = bool(read_checksum);
if(test(opts, get::CHECKSUM) && !test(opts, get::NO_CHECKSUM))
ret.verify_checksums = true;
ret.verify_checksums = opts.checksum <= -1?
bool(read_checksum):
opts.checksum;
if(test(opts, get::NO_SNAPSHOT))
if(opts.tailing)
ret.tailing = true;
if(test(opts, get::ORDERED))
if(opts.ordered)
ret.total_order_seek = true;
if(test(opts, get::PIN))
if(opts.pin)
ret.pin_data = true;
if(test(opts, get::CACHE))
if(opts.cache)
ret.fill_cache = true;
if(likely(test(opts, get::NO_CACHE)))
ret.fill_cache = false;
if(likely(test(opts, get::PREFIX)))
if(opts.prefix)
ret.prefix_same_as_start = true;
if(likely(test(opts, get::NO_BLOCKING)))
if(!opts.blocking)
ret.read_tier = rocksdb::ReadTier::kBlockCacheTier;
return ret;
@ -5318,13 +5309,11 @@ rocksdb::WriteOptions
ircd::db::make_opts(const sopts &opts)
{
rocksdb::WriteOptions ret;
//ret.no_slowdown = true; // read_tier = NON_BLOCKING for writes
ret.sync = test(opts, set::FSYNC);
ret.disableWAL = !enable_wal || test(opts, set::NO_JOURNAL);
ret.ignore_missing_column_families = test(opts, set::NO_COLUMN_ERR);
ret.no_slowdown = test(opts, set::NO_BLOCKING);
ret.low_pri = test(opts, set::PRIO_LOW);
ret.sync = opts.fsync;
ret.disableWAL = !enable_wal || !opts.journal;
ret.ignore_missing_column_families = true;
ret.no_slowdown = !opts.blocking;
ret.low_pri = opts.prio_low;
return ret;
}

View File

@ -89,7 +89,8 @@ ircd::m::events::dump__file(const string_view &filename)
{
static const db::gopts gopts
{
db::get::NO_CACHE, db::get::NO_CHECKSUM
.cache = false,
.checksum = false,
};
const fs::fd::opts fileopts
@ -313,13 +314,12 @@ ircd::m::events::source::for_each(const range &range,
range.second
};
db::gopts gopts
const db::gopts gopts
{
db::get::NO_CACHE,
db::get::NO_CHECKSUM
.cache = false,
.checksum = false,
.readahead = size_t(readahead) & boolmask<size_t>(ascending),
};
gopts.readahead = size_t(readahead);
gopts.readahead &= boolmask<size_t>(ascending);
auto it
{
@ -375,18 +375,18 @@ ircd::m::events::content::for_each(const closure &closure)
json::indexof<event, "content"_>()
};
const db::gopts gopts
{
.cache = false,
.checksum = false,
.readahead = size_t(readahead),
};
db::column &column
{
dbs::event_column.at(content_idx)
};
db::gopts gopts
{
db::get::NO_CACHE,
db::get::NO_CHECKSUM
};
gopts.readahead = size_t(readahead);
auto it(column.begin(gopts));
for(; it; ++it)
{
@ -432,12 +432,12 @@ ircd::m::events::refs::for_each(const range &range,
dbs::event_refs
};
db::gopts gopts
const db::gopts gopts
{
db::get::NO_CACHE,
db::get::NO_CHECKSUM
.cache = false,
.checksum = false,
.readahead = size_t(readahead),
};
gopts.readahead = size_t(readahead);
const auto start
{

View File

@ -251,7 +251,7 @@ try
//vmopts.phase.set(vm::phase::PREINDEX, true);
// Optimize the bootstrap by disabling WAL journaling.
vmopts.wopts.sopts |= db::set::NO_JOURNAL;
vmopts.wopts.sopts.journal = false;
// Optimize the bootstrap by not updating room heads at every step.
vmopts.wopts.appendix.set(dbs::appendix::ROOM_HEAD, false);

View File

@ -346,12 +346,15 @@ ircd::m::room::head::reset(const head &head)
size_t
ircd::m::room::head::rebuild(const head &head)
{
size_t ret{0};
static const m::event::fetch::opts fopts
{
{ db::get::NO_CACHE }
db::gopts
{
.cache = false,
},
};
size_t ret{0};
m::room::events it
{
head.room, 0UL, &fopts

View File

@ -46,7 +46,7 @@ ircd::m::room::stats::bytes_json(const m::room &room)
static const db::gopts gopts
{
db::get::NO_CACHE
.cache = false,
};
ret += db::bytes_value(m::dbs::event_json, key, gopts);

View File

@ -10143,8 +10143,10 @@ console_cmd__room__members__read(opt &out, const string_view &line)
{
"event_id", "content", "origin_server_ts", "sender"
},
db::gopts
{
db::get::NO_CACHE
.cache = false,
},
};