1
0
mirror of https://github.com/Zygo/bees.git synced 2025-05-18 05:45:45 +02:00

context: lock extents by bytenr instead of globally prohibiting tmpfiles

This prevents two threads from attempting to dispose of the same physical
extent at the same time.  This is a more precise exclusion than the
general lock on all tmpfiles.

Signed-off-by: Zygo Blaxell <bees@furryterror.org>
This commit is contained in:
Zygo Blaxell 2017-01-11 20:57:23 -05:00
parent e7fddcbc04
commit e46b96d23c
5 changed files with 24 additions and 28 deletions

View File

@ -252,6 +252,7 @@ BeesContext::home_fd()
BeesContext::BeesContext(shared_ptr<BeesContext> parent) : BeesContext::BeesContext(shared_ptr<BeesContext> parent) :
m_parent_ctx(parent) m_parent_ctx(parent)
{ {
m_extent_lock_set.max_size(bees_worker_thread_count());;
if (m_parent_ctx) { if (m_parent_ctx) {
m_fd_cache = m_parent_ctx->fd_cache(); m_fd_cache = m_parent_ctx->fd_cache();
} }
@ -440,9 +441,6 @@ BeesContext::scan_one_extent(const BeesFileRange &bfr, const Extent &e)
BEESTRACE(e << " block_count " << block_count); BEESTRACE(e << " block_count " << block_count);
string bar(block_count, '#'); string bar(block_count, '#');
// Only one thread may create tmpfiles at any given time
unique_lock<mutex> tmpfile_lock(bees_tmpfile_mutex, defer_lock);
for (off_t next_p = e.begin(); next_p < e.end(); ) { for (off_t next_p = e.begin(); next_p < e.end(); ) {
// Guarantee forward progress // Guarantee forward progress
@ -743,10 +741,6 @@ BeesContext::scan_one_extent(const BeesFileRange &bfr, const Extent &e)
// BEESLOG("noinsert_set.count(" << to_hex(p) << ") " << noinsert_set.count(p)); // BEESLOG("noinsert_set.count(" << to_hex(p) << ") " << noinsert_set.count(p));
if (noinsert_set.count(p)) { if (noinsert_set.count(p)) {
if (p - last_p > 0) { if (p - last_p > 0) {
if (!tmpfile_lock) {
BEESNOTE("waiting for tmpfile");
tmpfile_lock.lock();
}
rewrite_file_range(BeesFileRange(bfr.fd(), last_p, p)); rewrite_file_range(BeesFileRange(bfr.fd(), last_p, p));
blocks_rewritten = true; blocks_rewritten = true;
} }
@ -758,10 +752,6 @@ BeesContext::scan_one_extent(const BeesFileRange &bfr, const Extent &e)
} }
BEESTRACE("last"); BEESTRACE("last");
if (next_p - last_p > 0) { if (next_p - last_p > 0) {
if (!tmpfile_lock) {
BEESNOTE("waiting for tmpfile");
tmpfile_lock.lock();
}
rewrite_file_range(BeesFileRange(bfr.fd(), last_p, next_p)); rewrite_file_range(BeesFileRange(bfr.fd(), last_p, next_p));
blocks_rewritten = true; blocks_rewritten = true;
} }
@ -852,6 +842,9 @@ BeesContext::scan_forward(const BeesFileRange &bfr)
e = ew.current(); e = ew.current();
catch_all([&]() { catch_all([&]() {
uint64_t extent_bytenr = e.bytenr();
BEESNOTE("waiting for extent bytenr " << to_hex(extent_bytenr));
decltype(m_extent_lock_set)::Lock extent_lock(m_extent_lock_set, extent_bytenr);
Timer one_extent_timer; Timer one_extent_timer;
return_bfr = scan_one_extent(bfr, e); return_bfr = scan_one_extent(bfr, e);
BEESCOUNTADD(scanf_extent_ms, one_extent_timer.age() * 1000); BEESCOUNTADD(scanf_extent_ms, one_extent_timer.age() * 1000);
@ -950,8 +943,9 @@ BeesContext::set_root_fd(Fd fd)
m_root_uuid = fsinfo.uuid(); m_root_uuid = fsinfo.uuid();
BEESLOG("Filesystem UUID is " << m_root_uuid); BEESLOG("Filesystem UUID is " << m_root_uuid);
// 65536 is big enough for two max-sized extents // 65536 is big enough for two max-sized extents.
m_resolve_cache.max_size(65536); // Need enough total space in the cache for the maximum number of active threads.
m_resolve_cache.max_size(65536 * bees_worker_thread_count());
m_resolve_cache.func([&](BeesAddress addr) -> BeesResolveAddrResult { m_resolve_cache.func([&](BeesAddress addr) -> BeesResolveAddrResult {
return resolve_addr_uncached(addr); return resolve_addr_uncached(addr);
}); });

View File

@ -311,7 +311,7 @@ BeesHashTable::fetch_missing_extent(HashType hash)
BEESNOTE("waiting to fetch hash extent #" << extent_number << ", " << missing_buckets << " left to fetch"); BEESNOTE("waiting to fetch hash extent #" << extent_number << ", " << missing_buckets << " left to fetch");
// Acquire blocking lock on this extent only // Acquire blocking lock on this extent only
LockSet<uint64_t>::Lock extent_lock(m_extent_lock_set, extent_number); decltype(m_extent_lock_set)::Lock extent_lock(m_extent_lock_set, extent_number);
// Check missing again because someone else might have fetched this // Check missing again because someone else might have fetched this
// extent for us while we didn't hold any locks // extent for us while we didn't hold any locks

View File

@ -301,8 +301,7 @@ BeesRoots::BeesRoots(shared_ptr<BeesContext> ctx) :
m_crawl_state_file(ctx->home_fd(), crawl_state_filename()), m_crawl_state_file(ctx->home_fd(), crawl_state_filename()),
m_writeback_thread("crawl_writeback") m_writeback_thread("crawl_writeback")
{ {
unsigned max_crawlers = max(1U, thread::hardware_concurrency()); m_lock_set.max_size(bees_worker_thread_count());
m_lock_set.max_size(max_crawlers);
catch_all([&]() { catch_all([&]() {
state_load(); state_load();
@ -555,20 +554,22 @@ void
BeesCrawl::crawl_thread() BeesCrawl::crawl_thread()
{ {
Timer crawl_timer; Timer crawl_timer;
LockSet<uint64_t>::Lock crawl_lock(m_ctx->roots()->lock_set(), m_state.m_root, false);
while (!m_stopped) { while (!m_stopped) {
BEESNOTE("waiting for crawl thread limit " << m_state); BEESNOTE("waiting for crawl thread limit " << m_state);
LockSet<uint64_t>::Lock crawl_lock(m_ctx->roots()->lock_set(), m_state.m_root); crawl_lock.lock();
BEESNOTE("pop_front " << m_state);
auto this_range = pop_front(); auto this_range = pop_front();
crawl_lock.unlock();
if (this_range) { if (this_range) {
catch_all([&]() { catch_all([&]() {
// BEESINFO("scan_forward " << this_range); BEESNOTE("scan_forward " << this_range);
m_ctx->scan_forward(this_range); m_ctx->scan_forward(this_range);
}); });
BEESCOUNT(crawl_scan); BEESCOUNT(crawl_scan);
} else { } else {
auto crawl_time = crawl_timer.age(); auto crawl_time = crawl_timer.age();
BEESLOGNOTE("Crawl ran out of data after " << crawl_time << "s, waiting for more..."); BEESLOGNOTE("Crawl ran out of data after " << crawl_time << "s, waiting for more...");
crawl_lock.unlock();
unique_lock<mutex> lock(m_mutex); unique_lock<mutex> lock(m_mutex);
if (m_stopped) { if (m_stopped) {
break; break;

View File

@ -205,14 +205,6 @@ operator<<(ostream &os, const BeesStatTmpl<T> &bs)
* effectively crash the kernel. */ * effectively crash the kernel. */
mutex bees_ioctl_mutex; mutex bees_ioctl_mutex;
/**
* Don't allow two threads to create temporary copies of extent data at
* the same time. If two threads create temporary copies of the same
* extent at the same time they will not be properly deduped. This lock
* goes into effect as the first temporary extent is created by a thread,
* and is released after the source extent scan is finished. */
mutex bees_tmpfile_mutex;
template <class T> template <class T>
T& T&
BeesStatTmpl<T>::at(string idx) BeesStatTmpl<T>::at(string idx)
@ -568,6 +560,12 @@ BeesTempFile::make_copy(const BeesFileRange &src)
return rv; return rv;
} }
unsigned
bees_worker_thread_count()
{
return max(1U, thread::hardware_concurrency());
}
int int
bees_main(int argc, const char **argv) bees_main(int argc, const char **argv)
{ {

View File

@ -703,6 +703,8 @@ class BeesContext : public enable_shared_from_this<BeesContext> {
Timer m_total_timer; Timer m_total_timer;
LockSet<uint64_t> m_extent_lock_set;
void set_root_fd(Fd fd); void set_root_fd(Fd fd);
BeesResolveAddrResult resolve_addr_uncached(BeesAddress addr); BeesResolveAddrResult resolve_addr_uncached(BeesAddress addr);
@ -740,6 +742,7 @@ public:
shared_ptr<BeesTempFile> tmpfile(); shared_ptr<BeesTempFile> tmpfile();
const Timer &total_timer() const { return m_total_timer; } const Timer &total_timer() const { return m_total_timer; }
LockSet<uint64_t> &extent_lock_set() { return m_extent_lock_set; }
// TODO: move the rest of the FD cache methods here // TODO: move the rest of the FD cache methods here
void insert_root_ino(Fd fd); void insert_root_ino(Fd fd);
@ -828,6 +831,6 @@ extern RateLimiter bees_info_rate_limit;
void bees_sync(int fd); void bees_sync(int fd);
string format_time(time_t t); string format_time(time_t t);
extern mutex bees_ioctl_mutex; extern mutex bees_ioctl_mutex;
extern mutex bees_tmpfile_mutex; extern unsigned bees_worker_thread_count();
#endif #endif