0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2024-12-26 15:33:54 +01:00

ircd::db: Refactor opts to not store ilists; cleanup index/column relationship; cleanup where.

This commit is contained in:
Jason Volk 2017-09-21 20:08:11 -07:00
parent 48877a31c8
commit dae391a578
6 changed files with 240 additions and 225 deletions

View file

@ -32,6 +32,7 @@ namespace ircd::db
struct cell;
struct row;
struct column;
struct index;
struct database;
enum op :uint8_t;
enum class pos :int8_t;

View file

@ -114,8 +114,6 @@ struct ircd::db::column
bool operator!() const { return !c; }
// [GET] Iterations
const_iterator cbegin(const gopts & = {});
const_iterator cend(const gopts & = {});
const_iterator begin(const gopts & = {});
const_iterator end(const gopts & = {});
const_iterator find(const string_view &key, const gopts & = {});
@ -185,14 +183,14 @@ struct ircd::db::column::const_iterator
using iterator_category = std::bidirectional_iterator_tag;
protected:
friend class column;
database::column *c;
database::snapshot ss;
std::unique_ptr<rocksdb::Iterator> it;
mutable value_type val;
bool all_prefix;
friend class column;
const_iterator(database::column *const &, std::unique_ptr<rocksdb::Iterator> &&, const gopts & = {});
const_iterator(database::column *const &, std::unique_ptr<rocksdb::Iterator> &&, database::snapshot = {});
public:
explicit operator const database::snapshot &() const;
@ -220,7 +218,7 @@ struct ircd::db::column::const_iterator
friend bool operator<(const const_iterator &, const const_iterator &);
friend bool operator>(const const_iterator &, const const_iterator &);
template<class pos> friend bool seek(column::const_iterator &, const pos &);
template<class pos> friend bool seek(column::const_iterator &, const pos &, const gopts & = {});
};
inline ircd::db::column::const_iterator::operator

View file

@ -36,9 +36,11 @@ struct ircd::db::index
using iterator_type = const_iterator;
using const_iterator_type = const_iterator;
const_iterator end();
const_iterator begin();
const_iterator find(const string_view &key);
static const gopts applied_opts;
const_iterator end(const gopts & = {});
const_iterator begin(const gopts & = {});
const_iterator find(const string_view &key, const gopts & = {});
using column::column;
};
@ -46,9 +48,15 @@ struct ircd::db::index
struct ircd::db::index::const_iterator
:ircd::db::column::const_iterator
{
friend class index;
const value_type &operator*() const;
const value_type *operator->() const;
const_iterator(column::const_iterator it);
const_iterator() = default;
const_iterator &operator++();
const_iterator &operator--();
using column::const_iterator::const_iterator;
template<class pos> friend bool seek(index::const_iterator &, const pos &, gopts = {});
};

View file

@ -25,91 +25,125 @@
namespace ircd::db
{
template<class T> struct optval;
template<class T> using optlist = std::initializer_list<optval<T>>;
template<class T> bool has_opt(const optlist<T> &, const T &);
template<class T> ssize_t opt_val(const optlist<T> &, const T &);
enum class set :uint64_t;
enum class get :uint64_t;
enum class set;
template<class> struct opts;
struct sopts;
enum class get;
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);
}
template<class T>
struct ircd::db::optval
:std::pair<T, ssize_t>
{
optval(const T &key, const ssize_t &val = std::numeric_limits<ssize_t>::min());
};
enum class ircd::db::set
:uint64_t
{
FSYNC, // Uses kernel filesystem synchronization after write (slow)
NO_JOURNAL, // Write Ahead Log (WAL) for some crash recovery
MISSING_COLUMNS // No exception thrown when writing to a deleted column family
};
struct ircd::db::sopts
:optlist<set>
{
template<class... list>
sopts(list&&... l)
:optlist<set>{std::forward<list>(l)...}
{}
FSYNC = 0x0001, // Uses kernel filesystem synchronization after write (slow)
NO_JOURNAL = 0x0002, // Write Ahead Log (WAL) for some crash recovery
MISSING_COLUMNS = 0x0004, // No exception thrown when writing to a deleted column family
};
enum class ircd::db::get
:uint64_t
{
PIN, // Keep iter data in memory for iter lifetime (good for lots of ++/--)
CACHE, // Update the cache (CACHE is default for non-iterator operations)
NO_CACHE, // Do not update the cache (NO_CACHE is default for iterators)
NO_SNAPSHOT, // This iterator will have the latest data (tailing)
NO_CHECKSUM, // Integrity of data will be checked unless this is specified
READAHEAD, // Pair with a size in bytes for prefetching additional data
NO_EMPTY, // Option for db::row to not include unassigned cells in the row
ALL_PREFIX, // Iter all keys in prefix-oriented col (prefix_same_as_start = false)
};
struct ircd::db::gopts
:optlist<get>
{
database::snapshot snapshot;
template<class... list>
gopts(list&&... l)
:optlist<get>{std::forward<list>(l)...}
{}
PIN = 0x0001, // Keep iter data in memory for iter lifetime (good for lots of ++/--)
CACHE = 0x0002, // Update the cache (CACHE is default for non-iterator operations)
NO_CACHE = 0x0004, // Do not update the cache (NO_CACHE is default for iterators)
NO_SNAPSHOT = 0x0008, // This iterator will have the latest data (tailing)
NO_CHECKSUM = 0x0010, // Integrity of data will be checked unless this is specified
PREFIX = 0x0020, // Iteration over a single prefix in column (prefix_same_as_start)
};
template<class T>
ssize_t
ircd::db::opt_val(const optlist<T> &list,
const T &opt)
struct ircd::db::opts
{
for(const auto &p : list)
if(p.first == opt)
return p.second;
using flag_t = typename std::underlying_type<T>::type;
return std::numeric_limits<ssize_t>::min();
flag_t value {0};
opts() = default;
opts(const std::initializer_list<T> &list)
:value{combine_flags(list)}
{}
};
struct ircd::db::sopts
:opts<set>
{
using opts<set>::opts;
};
struct ircd::db::gopts
:opts<get>
{
database::snapshot snapshot;
size_t readahead { 4_KiB };
const rocksdb::Slice *upper_bound {nullptr};
using opts<get>::opts;
};
template<class T>
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>
ircd::db::opts<T> &
ircd::db::operator&=(opts<T> &a,
const opts<T> &b)
{
a.value &= b.value;
return a;
}
template<class T>
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>
ircd::db::opts<T> &
ircd::db::operator|=(opts<T> &a,
const opts<T> &b)
{
a.value |= b.value;
return a;
}
template<class T>
bool
ircd::db::has_opt(const optlist<T> &list,
const T &opt)
ircd::db::test(const opts<T> &a,
const T &value)
{
for(const auto &p : list)
if(p.first == opt)
return true;
using flag_t = typename opts<T>::flag_t;
return false;
return a.value & flag_t(value);
}
template<class T>
ircd::db::optval<T>::optval(const T &key,
const ssize_t &val)
:std::pair<T, ssize_t>{key, val}
bool
ircd::db::test(const opts<T> &a,
const typename std::underlying_type<T>::type &value)
{
return (a.value & value) == value;
}

View file

@ -62,31 +62,23 @@ struct ircd::db::where<tuple>::equal
:value{value}
{}
equal(json::members members)
:value{std::move(members)}
equal(const json::members &members)
:value{members}
{}
};
template<class tuple>
bool
ircd::db::where<tuple>::equal::operator()(const tuple &t)
ircd::db::where<tuple>::equal::operator()(const tuple &value)
const
{
return json::until(this->value, [&t]
(const auto &key, auto&& where_value)
return json::until(this->value, value, []
(const auto &key, const auto &a, const auto &b)
{
if(!where_value)
if(!a)
return true;
bool equal(true);
at(t, key, [&where_value, &equal]
(auto&& value)
{
//equal = value == where_value;
equal = (byte_view<>(value) == byte_view<>(where_value));
});
return equal;
return a == b;
});
}
@ -102,31 +94,23 @@ struct ircd::db::where<tuple>::not_equal
:value{value}
{}
not_equal(json::members members)
:value{std::move(members)}
not_equal(const json::members &members)
:value{members}
{}
};
template<class tuple>
bool
ircd::db::where<tuple>::not_equal::operator()(const tuple &t)
ircd::db::where<tuple>::not_equal::operator()(const tuple &value)
const
{
return json::until(this->value, [&t]
(const auto &key, auto&& where_value)
return !json::until(this->value, value, []
(const auto &key, const auto &a, const auto &b)
{
if(!where_value)
if(!a)
return true;
bool not_equal(true);
at(t, key, [&where_value, &not_equal]
(auto&& value)
{
//equal = value == where_value;
not_equal = (byte_view<>(value) != byte_view<>(where_value));
});
return not_equal;
return a == b;
});
}

View file

@ -49,8 +49,12 @@ namespace ircd::db
string_view slice(const rocksdb::Slice &);
// Frequently used get options and set options are separate from the string/map system
rocksdb::WriteOptions &operator+=(rocksdb::WriteOptions &, const sopts &);
rocksdb::ReadOptions &operator+=(rocksdb::ReadOptions &, const gopts &);
rocksdb::WriteOptions make_opts(const sopts &);
rocksdb::ReadOptions make_opts(const gopts &, const bool &iterator = false);
rocksdb::ReadOptions make_opts(const gopts &);
// Database options creator
bool optstr_find_and_remove(std::string &optstr, const std::string &what);
rocksdb::DBOptions make_dbopts(std::string &optstr, bool *read_only = nullptr, bool *fsck = nullptr);
template<class... args> rocksdb::DBOptions make_dbopts(const std::string &, args&&...);
@ -67,7 +71,7 @@ namespace ircd::db
void valid_eq_or_throw(const rocksdb::Iterator &, const string_view &);
// [GET] seek suite
template<class pos> bool seek(database::column &, const pos &, rocksdb::ReadOptions &, std::unique_ptr<rocksdb::Iterator> &it);
template<class pos> bool seek(database::column &, const pos &, const rocksdb::ReadOptions &, std::unique_ptr<rocksdb::Iterator> &it);
template<class pos> bool seek(database::column &, const pos &, const gopts &, std::unique_ptr<rocksdb::Iterator> &it);
std::unique_ptr<rocksdb::Iterator> seek(column &, const gopts &);
std::unique_ptr<rocksdb::Iterator> seek(column &, const string_view &key, const gopts &);
@ -1781,62 +1785,97 @@ ircd::db::iov::append::append(iov &t,
// db/index.h
//
ircd::db::index::const_iterator
ircd::db::index::find(const string_view &key)
const ircd::db::gopts
ircd::db::index::applied_opts
{
auto ret{column::lower_bound(key)};
if(!ret)
return const_iterator{};
{ get::PREFIX }
};
const auto &prefix(c->descriptor.prefix);
if(prefix.has && prefix.has(ret->first))
if(prefix.get && key != prefix.get(ret->first))
return const_iterator{};
template<class pos>
bool
ircd::db::seek(index::const_iterator &it,
const pos &p,
gopts opts)
{
opts |= index::applied_opts;
return seek(static_cast<column::const_iterator &>(it), p, opts);
}
template bool ircd::db::seek<ircd::db::pos>(index::const_iterator &, const pos &, gopts);
template bool ircd::db::seek<ircd::string_view>(index::const_iterator &, const string_view &, gopts);
return std::move(ret);
ircd::db::index::const_iterator
ircd::db::index::find(const string_view &key,
const gopts &opts)
{
const_iterator ret
{
c, {}, opts.snapshot
};
seek(ret, key, opts);
return ret;
}
ircd::db::index::const_iterator
ircd::db::index::begin()
ircd::db::index::begin(const gopts &opts)
{
return column::begin();
const_iterator ret
{
c, {}, opts.snapshot
};
seek(ret, pos::FRONT, opts);
return ret;
}
ircd::db::index::const_iterator
ircd::db::index::end()
ircd::db::index::end(const gopts &opts)
{
return column::end();
return {};
}
//
// const_iterator
//
ircd::db::index::const_iterator::const_iterator(column::const_iterator it)
:column::const_iterator{std::move(it)}
ircd::db::index::const_iterator &
ircd::db::index::const_iterator::operator--()
{
// const auto &prefix(c->descriptor.prefix);
// if(unlikely(!prefix.has || !prefix.get))
// throw schema_error("column '%s' has no prefix logic; it cannot be an index",
// name(*c));
seek(*this, pos::PREV);
return *this;
}
ircd::db::index::const_iterator &
ircd::db::index::const_iterator::operator++()
{
seek(*this, pos::NEXT);
return *this;
}
const ircd::db::index::const_iterator::value_type &
ircd::db::index::const_iterator::operator*()
const
{
const auto t(const_cast<const_iterator *>(this));
t->column::const_iterator::operator*();
string_view &key(t->val.first);
const auto &prefix(c->descriptor.prefix);
const auto &prefix
{
describe(*c).prefix
};
// Fetch the full value like a standard column first
column::const_iterator::operator*();
string_view &key{val.first};
// When there's no prefixing this index column is just
// like a normal column. Otherwise, we remove the prefix
// from the key the user will end up seeing.
if(prefix.has && prefix.has(key))
{
const auto first(prefix.get(key));
const auto second(key.substr(first.size()));
const auto &first(prefix.get(key));
const auto &second(key.substr(first.size()));
key = second;
}
return t->val;
return val;
}
const ircd::db::index::const_iterator::value_type *
@ -1924,7 +1963,7 @@ ircd::db::seek(cell &c,
gopts opts;
opts.snapshot = c.ss;
auto ropts(make_opts(opts));
const auto ropts(make_opts(opts));
return seek(dc, p, ropts, c.it);
}
template bool ircd::db::seek<ircd::db::pos>(cell &, const pos &);
@ -2742,30 +2781,17 @@ namespace db {
ircd::db::column::const_iterator
ircd::db::column::end(const gopts &gopts)
{
return cend(gopts);
return {};
}
ircd::db::column::const_iterator
ircd::db::column::begin(const gopts &gopts)
{
return cbegin(gopts);
}
ircd::db::column::const_iterator
ircd::db::column::cend(const gopts &gopts)
{
return {};
}
ircd::db::column::const_iterator
ircd::db::column::cbegin(const gopts &gopts)
{
const_iterator ret
{
c, {}, gopts
c, {}, gopts.snapshot
};
ret.all_prefix = true;
seek(ret, pos::FRONT);
return std::move(ret);
}
@ -2787,7 +2813,7 @@ ircd::db::column::find(const string_view &key,
{
auto it(lower_bound(key, gopts));
if(!it || it.it->key().compare(slice(key)) != 0)
return cend(gopts);
return end(gopts);
return it;
}
@ -2798,7 +2824,7 @@ ircd::db::column::lower_bound(const string_view &key,
{
const_iterator ret
{
c, {}, gopts
c, {}, gopts.snapshot
};
seek(ret, key);
@ -2811,7 +2837,6 @@ noexcept
,ss{std::move(o.ss)}
,it{std::move(o.it)}
,val{std::move(o.val)}
,all_prefix{std::move(o.all_prefix)}
{
}
@ -2823,7 +2848,6 @@ noexcept
ss = std::move(o.ss);
it = std::move(o.it);
val = std::move(o.val);
all_prefix = std::move(o.all_prefix);
return *this;
}
@ -2833,14 +2857,11 @@ ircd::db::column::const_iterator::const_iterator()
ircd::db::column::const_iterator::const_iterator(database::column *const &c,
std::unique_ptr<rocksdb::Iterator> &&it,
const gopts &gopts)
database::snapshot ss)
:c{c}
,ss{gopts.snapshot}
,ss{std::move(ss)}
,it{std::move(it)}
,all_prefix{has_opt(gopts, db::get::ALL_PREFIX)}
{
//if(!has_opt(this->opts, get::READAHEAD))
// this->gopts.readahead_size = DEFAULT_READAHEAD;
}
ircd::db::column::const_iterator::~const_iterator()
@ -2963,19 +2984,19 @@ ircd::db::operator<(const column::const_iterator &a, const column::const_iterato
template<class pos>
bool
ircd::db::seek(column::const_iterator &it,
const pos &p)
const pos &p,
const gopts &opts)
{
database::column &c(it);
auto opts
const auto ropts
{
make_opts({}, true)
make_opts(opts)
};
opts.prefix_same_as_start = !it.all_prefix;
return seek(c, p, opts, it.it);
return seek(c, p, ropts, it.it);
}
template bool ircd::db::seek<ircd::db::pos>(column::const_iterator &, const pos &);
template bool ircd::db::seek<ircd::string_view>(column::const_iterator &, const string_view &);
template bool ircd::db::seek<ircd::db::pos>(column::const_iterator &, const pos &, const gopts &);
template bool ircd::db::seek<ircd::string_view>(column::const_iterator &, const string_view &, const gopts &);
///////////////////////////////////////////////////////////////////////////////
//
@ -3150,7 +3171,7 @@ template<class pos>
bool
ircd::db::seek(database::column &c,
const pos &p,
rocksdb::ReadOptions &opts,
const rocksdb::ReadOptions &opts,
std::unique_ptr<rocksdb::Iterator> &it)
{
database &d(*c.d);
@ -3506,57 +3527,33 @@ ircd::db::optstr_find_and_remove(std::string &optstr,
}
rocksdb::ReadOptions
ircd::db::make_opts(const gopts &opts,
const bool &iterator)
ircd::db::make_opts(const gopts &opts)
{
rocksdb::ReadOptions ret;
ret.snapshot = opts.snapshot;
ret.read_tier = NON_BLOCKING;
ret.prefix_same_as_start = true;
//ret.total_order_seek = true;
ret.iterate_upper_bound = opts.upper_bound;
// slice* for exclusive upper bound. when prefixes are used this value must
// have the same prefix because ordering is not guaranteed between prefixes
//ret.iterate_upper_bound = nullptr;
if(iterator)
{
ret.fill_cache = false;
ret.readahead_size = 4_KiB;
}
else ret.fill_cache = true;
ret += opts;
return ret;
}
for(const auto &opt : opts) switch(opt.first)
{
case get::PIN:
ret.pin_data = true;
continue;
case get::CACHE:
ret.fill_cache = true;
continue;
case get::NO_CACHE:
ret.fill_cache = false;
continue;
case get::NO_SNAPSHOT:
ret.tailing = true;
continue;
case get::NO_CHECKSUM:
ret.verify_checksums = false;
continue;
case get::READAHEAD:
ret.readahead_size = opt.second;
continue;
case get::ALL_PREFIX:
ret.prefix_same_as_start = false;
continue;
default:
continue;
}
rocksdb::ReadOptions &
ircd::db::operator+=(rocksdb::ReadOptions &ret,
const gopts &opts)
{
if(opts.snapshot && !test(opts, get::NO_SNAPSHOT))
ret.snapshot = opts.snapshot;
ret.pin_data = test(opts, get::PIN);
ret.fill_cache |= test(opts, get::CACHE);
ret.fill_cache &= !test(opts, get::NO_CACHE);
ret.tailing = test(opts, get::NO_SNAPSHOT);
ret.verify_checksums = !test(opts, get::NO_CHECKSUM);
ret.prefix_same_as_start = test(opts, get::PREFIX);
return ret;
}
@ -3564,24 +3561,17 @@ rocksdb::WriteOptions
ircd::db::make_opts(const sopts &opts)
{
rocksdb::WriteOptions ret;
for(const auto &opt : opts) switch(opt.first)
{
case set::FSYNC:
ret.sync = true;
continue;
case set::NO_JOURNAL:
ret.disableWAL = true;
continue;
case set::MISSING_COLUMNS:
ret.ignore_missing_column_families = true;
continue;
default:
continue;
}
ret += opts;
return ret;
}
rocksdb::WriteOptions &
ircd::db::operator+=(rocksdb::WriteOptions &ret,
const sopts &opts)
{
ret.sync = test(opts, set::FSYNC);
ret.disableWAL = test(opts, set::NO_JOURNAL);
ret.ignore_missing_column_families = test(opts, set::MISSING_COLUMNS);
return ret;
}