mirror of
https://github.com/matrix-construct/construct
synced 2024-09-25 18:08:52 +02:00
ircd::db: Simplify options wrappings; eliminate bitflags.
This commit is contained in:
parent
4e7f5af457
commit
94a6cd0d90
9 changed files with 107 additions and 185 deletions
|
@ -46,8 +46,6 @@ struct ircd::db::domain
|
||||||
using iterator_type = const_iterator;
|
using iterator_type = const_iterator;
|
||||||
using const_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 end(const string_view &key, gopts = {});
|
||||||
const_iterator begin(const string_view &key, gopts = {});
|
const_iterator begin(const string_view &key, gopts = {});
|
||||||
const_reverse_iterator rend(const string_view &key, gopts = {});
|
const_reverse_iterator rend(const string_view &key, gopts = {});
|
||||||
|
|
|
@ -13,82 +13,72 @@
|
||||||
|
|
||||||
namespace ircd::db
|
namespace ircd::db
|
||||||
{
|
{
|
||||||
enum class set :uint64_t;
|
|
||||||
enum class get :uint64_t;
|
|
||||||
|
|
||||||
struct options;
|
|
||||||
template<class> struct opts;
|
|
||||||
struct sopts;
|
struct sopts;
|
||||||
struct gopts;
|
struct gopts;
|
||||||
|
struct options;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class ircd::db::set
|
/// Options for setting (writes)
|
||||||
: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)
|
|
||||||
struct ircd::db::sopts
|
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
|
struct ircd::db::gopts
|
||||||
:opts<get>
|
|
||||||
{
|
{
|
||||||
database::snapshot snapshot;
|
/// Keep iter data in memory for iter lifetime (good for lots ++/--).
|
||||||
const rocksdb::Slice *lower_bound { nullptr };
|
bool pin {false};
|
||||||
const rocksdb::Slice *upper_bound { nullptr };
|
|
||||||
size_t readahead { 0 };
|
|
||||||
|
|
||||||
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
|
/// options <-> string
|
||||||
|
@ -134,63 +124,3 @@ struct ircd::db::options::map
|
||||||
:std::unordered_map<std::string, std::string>{std::move(m)}
|
: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);
|
|
||||||
}
|
|
||||||
|
|
|
@ -72,7 +72,7 @@ struct ircd::m::dbs::write_opts
|
||||||
db::op op {db::op::SET};
|
db::op op {db::op::SET};
|
||||||
|
|
||||||
/// Lower-level write options passed to the transaction's execution.
|
/// 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
|
/// Principal's index number. Most codepaths do not permit zero. This may
|
||||||
/// be zero for blacklisting, but the blacklist option must be set.
|
/// be zero for blacklisting, but the blacklist option must be set.
|
||||||
|
|
59
ircd/db.cc
59
ircd/db.cc
|
@ -614,7 +614,7 @@ ircd::db::prefetcher::operator()(column &c,
|
||||||
// control queue growth, so we insert voluntary yield here to allow
|
// control queue growth, so we insert voluntary yield here to allow
|
||||||
// prefetch operations to at least be processed before returning to
|
// prefetch operations to at least be processed before returning to
|
||||||
// the user submitting more prefetches.
|
// the user submitting more prefetches.
|
||||||
if(likely(!test(opts, db::get::NO_BLOCKING)))
|
if(likely(opts.blocking))
|
||||||
ctx::yield();
|
ctx::yield();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -1725,15 +1725,15 @@ ircd::db::seek(row &r,
|
||||||
{
|
{
|
||||||
// If there's a pending error from another cell by the time this
|
// 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
|
// closure is executed we don't perform the seek() unless the user
|
||||||
// specifies db::get::NO_THROW to suppress it.
|
// specifies db::gopts::throwing=0 to suppress it.
|
||||||
if(!eptr || test(opts, get::NO_THROW)) try
|
if(!eptr || opts.throwing == false) try
|
||||||
{
|
{
|
||||||
if(!seek(cell, key))
|
if(!seek(cell, key))
|
||||||
{
|
{
|
||||||
// If the cell is not_found that's not a thrown exception here;
|
// If the cell is not_found that's not a thrown exception here;
|
||||||
// the cell will just be !valid(). The user can specify
|
// the cell will just be !valid(). The user can option
|
||||||
// get::THROW to propagate a not_found from the seek(row);
|
// throwing=1 to propagate a not_found from the seek(row).
|
||||||
if(test(opts, get::THROW))
|
if(opts.throwing == true)
|
||||||
throw not_found
|
throw not_found
|
||||||
{
|
{
|
||||||
"column '%s' key '%s'", cell.col(), key
|
"column '%s' key '%s'", cell.col(), key
|
||||||
|
@ -1787,7 +1787,7 @@ ircd::db::seek(row &r,
|
||||||
const bool submit
|
const bool submit
|
||||||
{
|
{
|
||||||
r.size() > 1 &&
|
r.size() > 1 &&
|
||||||
!test(opts, get::NO_PARALLEL) &&
|
opts.parallel &&
|
||||||
!db::cached(column, key, opts)
|
!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);
|
std::rethrow_exception(eptr);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -2346,12 +2346,6 @@ const
|
||||||
// db/domain.h
|
// db/domain.h
|
||||||
//
|
//
|
||||||
|
|
||||||
const ircd::db::gopts
|
|
||||||
ircd::db::domain::applied_opts
|
|
||||||
{
|
|
||||||
get::PREFIX
|
|
||||||
};
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
ircd::db::seek(domain::const_iterator_base &it,
|
ircd::db::seek(domain::const_iterator_base &it,
|
||||||
const pos &p)
|
const pos &p)
|
||||||
|
@ -2373,7 +2367,7 @@ ircd::db::seek(domain::const_iterator_base &it,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
it.opts |= domain::applied_opts;
|
it.opts.prefix = true;
|
||||||
return seek(static_cast<column::const_iterator_base &>(it), p);
|
return seek(static_cast<column::const_iterator_base &>(it), p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2381,7 +2375,7 @@ bool
|
||||||
ircd::db::seek(domain::const_iterator_base &it,
|
ircd::db::seek(domain::const_iterator_base &it,
|
||||||
const string_view &p)
|
const string_view &p)
|
||||||
{
|
{
|
||||||
it.opts |= domain::applied_opts;
|
it.opts.prefix = true;
|
||||||
return seek(static_cast<column::const_iterator_base &>(it), p);
|
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_lower_bound = opts.lower_bound;
|
||||||
ret.iterate_upper_bound = opts.upper_bound;
|
ret.iterate_upper_bound = opts.upper_bound;
|
||||||
|
|
||||||
ret.verify_checksums = bool(read_checksum);
|
ret.verify_checksums = opts.checksum <= -1?
|
||||||
if(test(opts, get::CHECKSUM) && !test(opts, get::NO_CHECKSUM))
|
bool(read_checksum):
|
||||||
ret.verify_checksums = true;
|
opts.checksum;
|
||||||
|
|
||||||
if(test(opts, get::NO_SNAPSHOT))
|
if(opts.tailing)
|
||||||
ret.tailing = true;
|
ret.tailing = true;
|
||||||
|
|
||||||
if(test(opts, get::ORDERED))
|
if(opts.ordered)
|
||||||
ret.total_order_seek = true;
|
ret.total_order_seek = true;
|
||||||
|
|
||||||
if(test(opts, get::PIN))
|
if(opts.pin)
|
||||||
ret.pin_data = true;
|
ret.pin_data = true;
|
||||||
|
|
||||||
if(test(opts, get::CACHE))
|
if(opts.cache)
|
||||||
ret.fill_cache = true;
|
ret.fill_cache = true;
|
||||||
|
|
||||||
if(likely(test(opts, get::NO_CACHE)))
|
if(opts.prefix)
|
||||||
ret.fill_cache = false;
|
|
||||||
|
|
||||||
if(likely(test(opts, get::PREFIX)))
|
|
||||||
ret.prefix_same_as_start = true;
|
ret.prefix_same_as_start = true;
|
||||||
|
|
||||||
if(likely(test(opts, get::NO_BLOCKING)))
|
if(!opts.blocking)
|
||||||
ret.read_tier = rocksdb::ReadTier::kBlockCacheTier;
|
ret.read_tier = rocksdb::ReadTier::kBlockCacheTier;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -5318,13 +5309,11 @@ rocksdb::WriteOptions
|
||||||
ircd::db::make_opts(const sopts &opts)
|
ircd::db::make_opts(const sopts &opts)
|
||||||
{
|
{
|
||||||
rocksdb::WriteOptions ret;
|
rocksdb::WriteOptions ret;
|
||||||
//ret.no_slowdown = true; // read_tier = NON_BLOCKING for writes
|
ret.sync = opts.fsync;
|
||||||
|
ret.disableWAL = !enable_wal || !opts.journal;
|
||||||
ret.sync = test(opts, set::FSYNC);
|
ret.ignore_missing_column_families = true;
|
||||||
ret.disableWAL = !enable_wal || test(opts, set::NO_JOURNAL);
|
ret.no_slowdown = !opts.blocking;
|
||||||
ret.ignore_missing_column_families = test(opts, set::NO_COLUMN_ERR);
|
ret.low_pri = opts.prio_low;
|
||||||
ret.no_slowdown = test(opts, set::NO_BLOCKING);
|
|
||||||
ret.low_pri = test(opts, set::PRIO_LOW);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -89,7 +89,8 @@ ircd::m::events::dump__file(const string_view &filename)
|
||||||
{
|
{
|
||||||
static const db::gopts gopts
|
static const db::gopts gopts
|
||||||
{
|
{
|
||||||
db::get::NO_CACHE, db::get::NO_CHECKSUM
|
.cache = false,
|
||||||
|
.checksum = false,
|
||||||
};
|
};
|
||||||
|
|
||||||
const fs::fd::opts fileopts
|
const fs::fd::opts fileopts
|
||||||
|
@ -313,13 +314,12 @@ ircd::m::events::source::for_each(const range &range,
|
||||||
range.second
|
range.second
|
||||||
};
|
};
|
||||||
|
|
||||||
db::gopts gopts
|
const db::gopts gopts
|
||||||
{
|
{
|
||||||
db::get::NO_CACHE,
|
.cache = false,
|
||||||
db::get::NO_CHECKSUM
|
.checksum = false,
|
||||||
|
.readahead = size_t(readahead) & boolmask<size_t>(ascending),
|
||||||
};
|
};
|
||||||
gopts.readahead = size_t(readahead);
|
|
||||||
gopts.readahead &= boolmask<size_t>(ascending);
|
|
||||||
|
|
||||||
auto it
|
auto it
|
||||||
{
|
{
|
||||||
|
@ -375,18 +375,18 @@ ircd::m::events::content::for_each(const closure &closure)
|
||||||
json::indexof<event, "content"_>()
|
json::indexof<event, "content"_>()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const db::gopts gopts
|
||||||
|
{
|
||||||
|
.cache = false,
|
||||||
|
.checksum = false,
|
||||||
|
.readahead = size_t(readahead),
|
||||||
|
};
|
||||||
|
|
||||||
db::column &column
|
db::column &column
|
||||||
{
|
{
|
||||||
dbs::event_column.at(content_idx)
|
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));
|
auto it(column.begin(gopts));
|
||||||
for(; it; ++it)
|
for(; it; ++it)
|
||||||
{
|
{
|
||||||
|
@ -432,12 +432,12 @@ ircd::m::events::refs::for_each(const range &range,
|
||||||
dbs::event_refs
|
dbs::event_refs
|
||||||
};
|
};
|
||||||
|
|
||||||
db::gopts gopts
|
const db::gopts gopts
|
||||||
{
|
{
|
||||||
db::get::NO_CACHE,
|
.cache = false,
|
||||||
db::get::NO_CHECKSUM
|
.checksum = false,
|
||||||
|
.readahead = size_t(readahead),
|
||||||
};
|
};
|
||||||
gopts.readahead = size_t(readahead);
|
|
||||||
|
|
||||||
const auto start
|
const auto start
|
||||||
{
|
{
|
||||||
|
|
|
@ -251,7 +251,7 @@ try
|
||||||
//vmopts.phase.set(vm::phase::PREINDEX, true);
|
//vmopts.phase.set(vm::phase::PREINDEX, true);
|
||||||
|
|
||||||
// Optimize the bootstrap by disabling WAL journaling.
|
// 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.
|
// Optimize the bootstrap by not updating room heads at every step.
|
||||||
vmopts.wopts.appendix.set(dbs::appendix::ROOM_HEAD, false);
|
vmopts.wopts.appendix.set(dbs::appendix::ROOM_HEAD, false);
|
||||||
|
|
|
@ -346,12 +346,15 @@ ircd::m::room::head::reset(const head &head)
|
||||||
size_t
|
size_t
|
||||||
ircd::m::room::head::rebuild(const head &head)
|
ircd::m::room::head::rebuild(const head &head)
|
||||||
{
|
{
|
||||||
size_t ret{0};
|
|
||||||
static const m::event::fetch::opts fopts
|
static const m::event::fetch::opts fopts
|
||||||
{
|
{
|
||||||
{ db::get::NO_CACHE }
|
db::gopts
|
||||||
|
{
|
||||||
|
.cache = false,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
size_t ret{0};
|
||||||
m::room::events it
|
m::room::events it
|
||||||
{
|
{
|
||||||
head.room, 0UL, &fopts
|
head.room, 0UL, &fopts
|
||||||
|
|
|
@ -46,7 +46,7 @@ ircd::m::room::stats::bytes_json(const m::room &room)
|
||||||
|
|
||||||
static const db::gopts gopts
|
static const db::gopts gopts
|
||||||
{
|
{
|
||||||
db::get::NO_CACHE
|
.cache = false,
|
||||||
};
|
};
|
||||||
|
|
||||||
ret += db::bytes_value(m::dbs::event_json, key, gopts);
|
ret += db::bytes_value(m::dbs::event_json, key, gopts);
|
||||||
|
|
|
@ -10143,8 +10143,10 @@ console_cmd__room__members__read(opt &out, const string_view &line)
|
||||||
{
|
{
|
||||||
"event_id", "content", "origin_server_ts", "sender"
|
"event_id", "content", "origin_server_ts", "sender"
|
||||||
},
|
},
|
||||||
|
|
||||||
|
db::gopts
|
||||||
{
|
{
|
||||||
db::get::NO_CACHE
|
.cache = false,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue