// JOURNAL_SEQ_NULL == JOURNAL_SEQ_MAX == journal_seq_t{}
constexpr journal_seq_t JOURNAL_SEQ_NULL = JOURNAL_SEQ_MAX;
+// logical offset between two laddr_t
+using loffset_t = uint64_t;
+
+// logical offset within an extent
+using extent_len_t = uint32_t;
+constexpr extent_len_t EXTENT_LEN_MAX =
+ std::numeric_limits<extent_len_t>::max();
+
+using extent_len_le_t = ceph_le32;
+inline extent_len_le_t init_extent_len_le(extent_len_t len) {
+ return ceph_le32(len);
+}
+
// logical addr, see LBAManager, TransactionManager
class laddr_t {
public:
std::numeric_limits<Unsigned>::max();
constexpr laddr_t() : laddr_t(RAW_VALUE_MAX) {}
- constexpr explicit laddr_t(Unsigned value) : value(value) {}
- bool is_aligned(Unsigned alignment) const {
- assert(alignment != 0);
- assert((alignment & (alignment - 1)) == 0);
- return value == p2align(value, alignment);
- }
+ // laddr_t is block aligned, one logical address represents one 4KiB block in disk
+ static constexpr unsigned UNIT_SHIFT = 12;
+ static constexpr unsigned UNIT_SIZE = 1 << UNIT_SHIFT; // 4096
+ static constexpr unsigned UNIT_MASK = UNIT_SIZE - 1;
- laddr_t get_aligned_laddr(Unsigned alignment) const {
- assert(alignment != 0);
- assert((alignment & (alignment - 1)) == 0);
- return laddr_t(p2align(value, alignment));
+ static laddr_t from_byte_offset(Unsigned value) {
+ assert((value & UNIT_MASK) == 0);
+ return laddr_t(value >> UNIT_SHIFT);
}
- laddr_t get_roundup_laddr(Unsigned alignment) const {
- assert(alignment != 0);
- assert((alignment & (alignment - 1)) == 0);
- return laddr_t(p2roundup(value, alignment));
+ static constexpr laddr_t from_raw_uint(Unsigned v) {
+ return laddr_t(v);
}
/// laddr_t works like primitive integer type, encode/decode it manually
memcpy((char *)&value, p.get_pos_add(sizeof(Unsigned)), sizeof(Unsigned));
}
- friend std::ostream &operator<<(std::ostream &, const laddr_t &);
+ // laddr_offset_t contains one base laddr and one block not aligned
+ // offset(< laddr_t::UNIT_SIZE). It is the return type of plus/minus
+ // overloads for laddr_t and loffset_t.
+ struct laddr_offset_t {
+ explicit laddr_offset_t(laddr_t base)
+ : base(base.value), offset(0) {}
+ laddr_offset_t(laddr_t base, extent_len_t offset)
+ : base(base.value), offset(offset) {
+ assert(offset < laddr_t::UNIT_SIZE);
+ }
- friend auto operator<=>(const laddr_t&, const laddr_t&) = default;
+ laddr_t get_roundup_laddr() const {
+ if (offset == 0) {
+ return laddr_t(base);
+ } else {
+ assert(offset < laddr_t::UNIT_SIZE);
+ return laddr_t(base + 1);
+ }
+ }
+ laddr_t get_aligned_laddr() const { return laddr_t(base); }
+ extent_len_t get_offset() const {
+ assert(offset < laddr_t::UNIT_SIZE);
+ return offset;
+ }
+ laddr_t checked_to_laddr() const {
+ assert(offset == 0);
+ return laddr_t(base);
+ }
+
+ template<std::unsigned_integral U>
+ U get_byte_distance(const laddr_t &l) const {
+ assert(offset < UNIT_SIZE);
+ if (base >= l.value) {
+ Unsigned udiff = base - l.value;
+ assert(udiff <= (std::numeric_limits<U>::max() >> UNIT_SHIFT));
+ return (static_cast<U>(udiff) << UNIT_SHIFT) + offset;
+ } else { // base < l.value
+ Unsigned udiff = l.value - base;
+ assert(udiff <= (std::numeric_limits<U>::max() >> UNIT_SHIFT));
+ return (static_cast<U>(udiff) << UNIT_SHIFT) - offset;
+ }
+ }
+
+ template<std::unsigned_integral U>
+ U get_byte_distance(const laddr_offset_t &l) const {
+ assert(offset < UNIT_SIZE);
+ if (*this >= l) {
+ Unsigned udiff = base - l.base;
+ assert(udiff <= (std::numeric_limits<U>::max() >> UNIT_SHIFT));
+ return ((static_cast<U>(udiff) << UNIT_SHIFT) + offset) - l.offset;
+ } else { // *this < l
+ Unsigned udiff = l.base - base;
+ assert(udiff <= (std::numeric_limits<U>::max() >> UNIT_SHIFT));
+ return ((static_cast<U>(udiff) << UNIT_SHIFT) + l.offset) - offset;
+ }
+ }
+
+ friend bool operator==(const laddr_offset_t&, const laddr_offset_t&) = default;
+ friend auto operator<=>(const laddr_offset_t&, const laddr_offset_t&) = default;
+ friend std::ostream &operator<<(std::ostream&, const laddr_offset_t&);
+ friend laddr_offset_t operator+(const laddr_offset_t &laddr_offset,
+ const loffset_t &offset) {
+ // laddr_offset_t could access (laddr_t + loffset_t) overload.
+ return laddr_offset.get_aligned_laddr()
+ + (laddr_offset.get_offset() + offset);
+ }
+ friend laddr_offset_t operator+(const loffset_t &offset,
+ const laddr_offset_t &loffset) {
+ return loffset + offset;
+ }
+
+ friend laddr_offset_t operator-(const laddr_offset_t &laddr_offset,
+ const loffset_t &offset) {
+ if (laddr_offset.get_offset() >= offset) {
+ return laddr_offset_t(
+ laddr_offset.get_aligned_laddr(),
+ laddr_offset.get_offset() - offset);
+ } else {
+ // laddr_offset_t could access (laddr_t - loffset_t) overload.
+ return laddr_offset.get_aligned_laddr()
+ - (offset - laddr_offset.get_offset());
+ }
+ }
+
+ friend class laddr_t;
+ private:
+ // use Unsigned here to avoid incomplete type of laddr_t
+ Unsigned base;
+ extent_len_t offset;
+ };
- friend laddr_t operator+(const laddr_t &laddr, const Unsigned &i) {
- return laddr_t{laddr.value + i};
+ template<std::unsigned_integral U>
+ U get_byte_distance(const laddr_offset_t &l) const {
+ if (value <= l.base) {
+ Unsigned udiff = l.base - value;
+ assert(udiff <= (std::numeric_limits<U>::max() >> UNIT_SHIFT));
+ return (static_cast<U>(udiff) << UNIT_SHIFT) + l.offset;
+ } else { // value > l.base
+ Unsigned udiff = value - l.base;
+ assert(udiff <= (std::numeric_limits<U>::max() >> UNIT_SHIFT));
+ return (static_cast<U>(udiff) << UNIT_SHIFT) - l.offset;
+ }
}
- friend laddr_t operator+(const Unsigned &i, const laddr_t &laddr) {
- return laddr_t{laddr.value + i};
+ template<std::unsigned_integral U>
+ U get_byte_distance(const laddr_t &l) const {
+ Unsigned diff = value > l.value
+ ? value - l.value
+ : l.value - value;
+ assert(diff <= (std::numeric_limits<U>::max() >> UNIT_SHIFT));
+ return static_cast<U>(diff) << UNIT_SHIFT;
}
- friend laddr_t operator-(const laddr_t &laddr, const Unsigned &i) {
- return laddr_t{laddr.value - i};
+ friend std::ostream &operator<<(std::ostream &, const laddr_t &);
+ friend bool operator==(const laddr_t&, const laddr_t&) = default;
+ friend bool operator==(const laddr_t &laddr,
+ const laddr_offset_t &laddr_offset) {
+ return laddr == laddr_offset.get_aligned_laddr()
+ && 0 == laddr_offset.get_offset();
+ }
+ friend bool operator==(const laddr_offset_t &laddr_offset,
+ const laddr_t &laddr) {
+ return laddr_offset.get_aligned_laddr() == laddr
+ && laddr_offset.get_offset() == 0;
+ }
+ friend auto operator<=>(const laddr_t&, const laddr_t&) = default;
+ friend auto operator<=>(const laddr_t &laddr,
+ const laddr_offset_t &laddr_offset) {
+ return laddr_offset_t(laddr, 0) <=> laddr_offset;
+ }
+ friend auto operator<=>(const laddr_offset_t &laddr_offset,
+ const laddr_t &laddr) {
+ return laddr_offset <=> laddr_offset_t(laddr, 0);
}
- friend Unsigned operator-(const laddr_t &l, const laddr_t &r) {
- return l.value - r.value;
+ friend laddr_offset_t operator+(const laddr_t &laddr,
+ const loffset_t &offset) {
+ auto base = laddr;
+ base.value += offset >> laddr_t::UNIT_SHIFT;
+ assert(base.value >= laddr.value);
+ return laddr_offset_t(base, offset & laddr_t::UNIT_MASK);
+ }
+ friend laddr_offset_t operator+(const loffset_t &offset,
+ const laddr_t &laddr) {
+ return laddr + offset;
+ }
+
+ friend laddr_offset_t operator-(const laddr_t &laddr, loffset_t offset) {
+ auto base = laddr;
+ auto diff = (offset + laddr_t::UNIT_SIZE - 1) >> laddr_t::UNIT_SHIFT;
+ base.value -= diff;
+ assert(base.value <= laddr.value);
+ offset = (diff << laddr_t::UNIT_SHIFT) - offset;
+ return laddr_offset_t(base, offset);
}
friend struct laddr_le_t;
friend struct pladdr_le_t;
private:
+ // Prevent direct construction of laddr_t with an integer,
+ // always use laddr_t::from_raw_uint instead.
+ constexpr explicit laddr_t(Unsigned value) : value(value) {}
Unsigned value;
};
+using laddr_offset_t = laddr_t::laddr_offset_t;
-constexpr laddr_t L_ADDR_MAX = laddr_t(laddr_t::RAW_VALUE_MAX);
-constexpr laddr_t L_ADDR_MIN = laddr_t(0);
+constexpr laddr_t L_ADDR_MAX = laddr_t::from_raw_uint(laddr_t::RAW_VALUE_MAX);
+constexpr laddr_t L_ADDR_MIN = laddr_t::from_raw_uint(0);
constexpr laddr_t L_ADDR_NULL = L_ADDR_MAX;
-constexpr laddr_t L_ADDR_ROOT = laddr_t(laddr_t::RAW_VALUE_MAX - 1);
-constexpr laddr_t L_ADDR_LBAT = laddr_t(laddr_t::RAW_VALUE_MAX - 2);
+constexpr laddr_t L_ADDR_ROOT = laddr_t::from_raw_uint(laddr_t::RAW_VALUE_MAX - 1);
+constexpr laddr_t L_ADDR_LBAT = laddr_t::from_raw_uint(laddr_t::RAW_VALUE_MAX - 2);
struct __attribute__((packed)) laddr_le_t {
ceph_le64 laddr;
static constexpr paddr_t null = P_ADDR_NULL;
};
-// logical offset, see LBAManager, TransactionManager
-using extent_len_t = uint32_t;
-constexpr extent_len_t EXTENT_LEN_MAX =
- std::numeric_limits<extent_len_t>::max();
-
-using extent_len_le_t = ceph_le32;
-inline extent_len_le_t init_extent_len_le(extent_len_t len) {
- return ceph_le32(len);
-}
-
using extent_ref_count_t = uint32_t;
constexpr extent_ref_count_t EXTENT_DEFAULT_REF_COUNT = 1;
template <> struct fmt::formatter<crimson::os::seastore::journal_seq_t> : fmt::ostream_formatter {};
template <> struct fmt::formatter<crimson::os::seastore::journal_tail_delta_t> : fmt::ostream_formatter {};
template <> struct fmt::formatter<crimson::os::seastore::laddr_t> : fmt::ostream_formatter {};
+template <> struct fmt::formatter<crimson::os::seastore::laddr_offset_t> : fmt::ostream_formatter {};
template <> struct fmt::formatter<crimson::os::seastore::laddr_list_t> : fmt::ostream_formatter {};
template <> struct fmt::formatter<crimson::os::seastore::omap_root_t> : fmt::ostream_formatter {};
template <> struct fmt::formatter<crimson::os::seastore::paddr_list_t> : fmt::ostream_formatter {};