Skip to content

Commit f89adea

Browse files
rlyerlymeta-codesync[bot]
authored andcommitted
Properly move items stored in inline Handle buffers
Summary: Don't just memcpy, actually move the items stored in the inline Handle buffer. This allows properly moving items, including those with self-references (the CacheItem sub-class needs to know how to move). Reviewed By: pbhandar2 Differential Revision: D100844276 fbshipit-source-id: 3bbb9b80d5e85d7b55418bdda9fc732cfa9e0fd0
1 parent 309ac21 commit f89adea

6 files changed

Lines changed: 29 additions & 10 deletions

File tree

cachelib/interface/CacheItem.h

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,13 @@ class CacheItem {
3030
CacheItem() = default;
3131
virtual ~CacheItem() = default;
3232

33-
// CacheItem is not copyable or movable
33+
// CacheItem is not copyable
3434
CacheItem(const CacheItem&) = delete;
3535
CacheItem& operator=(const CacheItem&) = delete;
36-
CacheItem(CacheItem&&) = delete;
37-
CacheItem& operator=(CacheItem&&) = delete;
36+
37+
// CacheItem is movable
38+
CacheItem(CacheItem&&) noexcept = default;
39+
CacheItem& operator=(CacheItem&&) noexcept = default;
3840

3941
// ------------------------------ Interface ------------------------------ //
4042

@@ -102,6 +104,11 @@ class CacheItem {
102104
* @return total size of cache item
103105
*/
104106
virtual uint32_t getTotalSize() const noexcept = 0;
107+
108+
private:
109+
virtual void move(void* dest) noexcept = 0;
110+
111+
friend class Handle;
105112
};
106113

107114
} // namespace facebook::cachelib::interface

cachelib/interface/Handle.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@
1818

1919
#include <folly/logging/xlog.h>
2020

21-
#include <cstring>
22-
2321
#include "cachelib/interface/CacheComponent.h"
2422

2523
namespace facebook::cachelib::interface {
@@ -38,7 +36,8 @@ Handle::Handle(Handle&& other) noexcept
3836
: cache_(other.cache_), inserted_(other.inserted_) {
3937
XDCHECK_NE(cache_, nullptr) << "Invalid handle";
4038
if (other.item_ == reinterpret_cast<CacheItem*>(other.buf_)) {
41-
std::memcpy(buf_, other.buf_, kInlineBufSize);
39+
other.item_->move(buf_);
40+
other.item_->~CacheItem();
4241
item_ = reinterpret_cast<CacheItem*>(buf_);
4342
} else {
4443
item_ = other.item_;

cachelib/interface/Handle.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,10 +72,6 @@ class Handle {
7272
* Note: the caller is responsible for incrementing the item's refcount after
7373
* allocating it in the inline buffer
7474
*
75-
* Note: the Handle move constructor relocates inline items via memcpy. This
76-
* is safe only if the item type has no self-referential pointers (i.e.,
77-
* members that point to other members or to `this`).
78-
*
7975
* @param cache the cache component that owns the cache item
8076
* @param inserted whether the cache item has been inserted into cache
8177
*/

cachelib/interface/components/FlashCacheComponent.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,10 @@ class FlashCacheItem : public CacheItem {
147147
// Allocation and findToWrite paths use MutableBufferView (points into region
148148
// buffer). Find path uses Buffer (owned copy from device read).
149149
std::variant<Buffer, MutableBufferView> data_;
150+
151+
void move(void* dest) noexcept override {
152+
new (dest) FlashCacheItem(std::move(*this));
153+
}
150154
};
151155

152156
static_assert(sizeof(FlashCacheItem) <= Handle::kInlineBufSize,
@@ -656,6 +660,10 @@ class ConsistentFlashCacheItem : public FlashCacheItem {
656660

657661
private:
658662
utils::ShardedSerializer::WriteLock lock_;
663+
664+
void move(void* dest) noexcept override {
665+
new (dest) ConsistentFlashCacheItem(std::move(*this));
666+
}
659667
};
660668

661669
static_assert(sizeof(ConsistentFlashCacheItem) <= Handle::kInlineBufSize,

cachelib/interface/components/RAMCacheComponent.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,11 @@ class RAMCacheItem : public interface::CacheItem {
9191
LruCacheItem* item_;
9292

9393
explicit RAMCacheItem(LruCacheItem* item) : item_(item) {}
94+
95+
void move(void* /* dest */) noexcept override {
96+
// We don't use the inline Handle buffer, move() should never be called
97+
XLOG(FATAL) << "Should not use RAMCacheItem::move()";
98+
}
9499
};
95100
// RAMCacheItem should only contain vtable and LruCacheItem pointers
96101
static_assert(sizeof(RAMCacheItem) == (2 * sizeof(void*)));

cachelib/interface/tests/InterfaceTest.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ class TestCacheItem : public CacheItem {
5555
std::string key_;
5656
std::vector<uint8_t> memory_;
5757
std::atomic_size_t refCount_;
58+
59+
void move(void* /* dest */) noexcept override {
60+
XLOG(FATAL) << "Should not use TestCacheItem::move()";
61+
}
5862
};
5963

6064
class TestCacheComponent : public CacheComponent {

0 commit comments

Comments
 (0)