1
0
mirror of https://github.com/Zygo/bees.git synced 2025-05-17 21:35:45 +02:00
bees/include/crucible/extentwalker.h
Zygo Blaxell d4b3836493 extentwalker: don't fetch absurd numbers of extents just to throw them away
ExtentWalker doesn't gain significant benefits from caching, and the
extra SEARCH_V2 ioctls were blamed for a 33% kernel CPU overhead by perf.

Reduce the number of extents to 16 in lieu of fixing the caching.

This gives a significant speed boost on CPU-bound workloads compared
to the original 1024--almost 40% faster on a single SSD with a filesystem
consisting of raw VM images mounted with compress=zstd.

This also seems to reduce LOGICAL_INO overhead.  Perhaps SEARCH_V2 and
LOGICAL_INO were trying to lock the same extents, and interfering with
each other?

Signed-off-by: Zygo Blaxell <bees@furryterror.org>
2018-09-26 23:29:56 -04:00

104 lines
2.5 KiB
C++

#ifndef CRUCIBLE_EXTENTWALKER_H
#define CRUCIBLE_EXTENTWALKER_H
#include "crucible/fd.h"
namespace crucible {
using namespace std;
// FIXME: ExtentCursor is probably a better name
struct Extent {
off_t m_begin = 0;
off_t m_end = 0;
uint64_t m_physical = 0;
uint64_t m_flags = 0;
// Btrfs extent reference details
off_t m_physical_len = 0;
off_t m_logical_len = 0;
off_t m_offset = 0;
// fiemap flags are uint32_t, so bits 32..63 are OK for us
// no extent here
static const uint64_t HOLE = (1ULL << 32);
// extent is physical space full of zeros
static const uint64_t PREALLOC = (1ULL << 33);
// extent's physical (RAM) size does not match logical (can we know this?)
static const uint64_t OBSCURED = (1ULL << 34);
operator bool() const;
off_t size() const;
off_t begin() const { return m_begin; }
off_t end() const { return m_end; }
uint64_t flags() const { return m_flags; }
uint64_t physical() const { return m_physical; }
off_t physical_len() const { return m_physical_len; }
off_t logical_len() const { return m_logical_len; }
off_t offset() const { return m_offset; }
bool compressed() const;
uint64_t bytenr() const;
bool operator==(const Extent &that) const;
bool operator!=(const Extent &that) const { return !(*this == that); }
Extent() = default;
Extent(const Extent &e) = default;
};
class ExtentWalker {
public:
using Vec = vector<Extent>;
using Itr = Vec::iterator;
protected:
Fd m_fd;
Stat m_stat;
virtual Vec get_extent_map(off_t pos);
static const unsigned sc_extent_fetch_max = 16;
static const unsigned sc_extent_fetch_min = 4;
static const off_t sc_step_size = 0x1000 * (sc_extent_fetch_max / 2);
private:
Vec m_extents;
Itr m_current;
Itr find_in_cache(off_t pos);
void run_fiemap(off_t pos);
public:
ExtentWalker(Fd fd = Fd());
ExtentWalker(Fd fd, off_t initial_pos);
virtual ~ExtentWalker();
void reset();
Extent current();
bool next();
bool prev();
void seek(off_t new_pos);
friend ostream & operator<<(ostream &os, const ExtentWalker &ew);
};
class BtrfsExtentWalker : public ExtentWalker {
uint64_t m_tree_id;
Fd m_root_fd;
protected:
Vec get_extent_map(off_t pos) override;
public:
BtrfsExtentWalker(Fd fd);
BtrfsExtentWalker(Fd fd, off_t initial_pos);
BtrfsExtentWalker(Fd fd, off_t initial_pos, Fd root_fd);
void set_root_fd(Fd fd);
};
ostream &operator<<(ostream &os, const Extent &e);
};
#endif // CRUCIBLE_EXTENTWALKER_H