0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2024-11-17 15:30:52 +01:00

ircd::db: Enrich seek(row) opts; add proper error handling and propagation.

This commit is contained in:
Jason Volk 2018-12-24 14:33:35 -08:00
parent b035bb9824
commit c1c11b4aed
3 changed files with 68 additions and 19 deletions

View file

@ -50,6 +50,9 @@ enum class ircd::db::get
NO_CHECKSUM = 0x0020, // Integrity of data will not be checked (overrides conf). NO_CHECKSUM = 0x0020, // Integrity of data will not be checked (overrides conf).
PREFIX = 0x0040, // (prefix_same_as_start); automatic for index columns with pfx PREFIX = 0x0040, // (prefix_same_as_start); automatic for index columns with pfx
ORDERED = 0x0080, // (total_order_seek); relevant to index columns ORDERED = 0x0080, // (total_order_seek); relevant to index columns
NO_PARALLEL = 0x0100, // Don't submit requests in parallel (relevant to db::row)
NO_THROW = 0x0200, // Suppress exceptions if possible.
THROW = 0x0400, // Throw exceptions more than usual.
}; };
template<class T> template<class T>

View file

@ -60,7 +60,7 @@ struct ircd::db::row
gopts opts = {}) gopts opts = {})
__attribute__((stack_protect)); __attribute__((stack_protect));
friend size_t seek(row &, const string_view &); friend size_t seek(row &, const string_view &, const gopts &opts = {});
}; };
namespace ircd::db namespace ircd::db

View file

@ -9005,58 +9005,104 @@ ircd::db::write(const row::delta *const &begin,
size_t size_t
ircd::db::seek(row &r, ircd::db::seek(row &r,
const string_view &key) const string_view &key,
const gopts &opts)
{ {
// This frame can't be interrupted because it may have requests
// pending in the request pool which must synchronize back here.
const ctx::uninterruptible ui;
#ifdef RB_DEBUG_DB_SEEK #ifdef RB_DEBUG_DB_SEEK
const ircd::timer timer; const ircd::timer timer;
#endif #endif
// This frame can't be interrupted because it may have requests
// pending in the request pool which must synchronize back here.
const ctx::uninterruptible ui;
size_t ret{0}; size_t ret{0};
std::exception_ptr eptr;
ctx::latch latch{r.size()}; ctx::latch latch{r.size()};
const auto closure{[&latch, &ret, &key] const auto closure{[&opts, &latch, &ret, &key, &eptr]
(auto &cell) (auto &cell) noexcept
{ {
ret += bool(seek(cell, key)); // 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
{
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))
throw not_found
{
"column '%s' key '%s'", cell.col(), key
};
}
else ++ret;
}
catch(const not_found &e)
{
eptr = std::current_exception();
}
catch(const std::exception &e)
{
log::error
{
log, "row seek: column '%s' key '%s' :%s",
cell.col(),
key,
e.what()
};
eptr = std::make_exception_ptr(e);
}
// The latch must always be hit here. No exception should propagate
// to prevent this from being reached or beyond.
latch.count_down(); latch.count_down();
}}; }};
// Submit all the requests
for(auto &cell : r) for(auto &cell : r)
{ {
db::column &column(cell); db::column &column(cell);
const auto reclosure{[&closure, &cell]
{
closure(cell);
}};
//TODO: should check a bloom filter on the cache for this branch //TODO: should check a bloom filter on the cache for this branch
//TODO: because right now double-querying the cache is gross. //TODO: because right now double-querying the cache is gross.
if(!exists(cache(column), key)) if(!test(opts, get::NO_PARALLEL) && !exists(cache(column), key))
request([&closure, &cell] request(reclosure);
{
closure(cell);
});
else else
closure(cell); reclosure();
} }
// Wait for responses.
latch.wait(); latch.wait();
assert(ret <= r.size());
#ifdef RB_DEBUG_DB_SEEK #ifdef RB_DEBUG_DB_SEEK
const column &c(r[0]); const column &c(r[0]);
const database &d(c); const database &d(c);
log::debug log::debug
{ {
log, "'%s' %lu:%lu '%s' row SEEK KEY %zu of %zu in %ld$us", log, "'%s' %lu:%lu '%s' row SEEK KEY %zu of %zu in %ld$us %s",
name(d), name(d),
sequence(d), sequence(d),
sequence(r[0]), sequence(r[0]),
name(c), name(c),
ret, ret,
r.size(), r.size(),
timer.at<microseconds>().count() timer.at<microseconds>().count(),
what(eptr)
}; };
#endif #endif
assert(ret <= r.size()); if(eptr && !test(opts, get::NO_THROW))
std::rethrow_exception(eptr);
return ret; return ret;
} }
@ -9144,7 +9190,7 @@ ircd::db::row::row(database &d,
} }
if(key) if(key)
seek(*this, key); seek(*this, key, opts);
} }
#pragma GCC diagnostic pop #pragma GCC diagnostic pop