Skip to content

Commit 07badaa

Browse files
generatedunixname1261038932274330meta-codesync[bot]
authored andcommitted
www/fbcode/glean/rts/cache.cpp
Reviewed By: malanka Differential Revision: D101133385 fbshipit-source-id: 5ec17b5ad38fced8e70d0ad87749a305a470fb77
1 parent 1549bac commit 07badaa

1 file changed

Lines changed: 262 additions & 0 deletions

File tree

glean/rts/tests/CacheTest.cpp

Lines changed: 262 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,63 @@ struct ConstantLookup : public Lookup {
6363
}
6464
};
6565

66+
// A Lookup that tracks calls and can return nothing (simulating missing facts)
67+
struct TrackingLookup : public Lookup {
68+
int idByKeyCalls = 0;
69+
int typeByIdCalls = 0;
70+
int factByIdCalls = 0;
71+
bool returnEmpty = false;
72+
73+
Id idByKey(Pid, folly::ByteRange) override {
74+
++idByKeyCalls;
75+
return returnEmpty ? Id::invalid() : Id::lowest();
76+
}
77+
Pid typeById(Id) override {
78+
++typeByIdCalls;
79+
return returnEmpty ? Pid::invalid() : Pid::lowest();
80+
}
81+
bool factById(Id, std::function<void(Pid, Fact::Clause)> f) override {
82+
++factByIdCalls;
83+
if (returnEmpty) {
84+
return false;
85+
}
86+
static unsigned char clause[] = "Helloworld";
87+
f(Pid::lowest(), {clause, 5, 5});
88+
return true;
89+
}
90+
91+
Id startingId() const override {
92+
return Id::lowest();
93+
}
94+
Id firstFreeId() const override {
95+
return Id::lowest() + 100;
96+
}
97+
std::unique_ptr<FactIterator> enumerate(Id, Id) override {
98+
return std::make_unique<EmptyIterator>();
99+
}
100+
std::unique_ptr<FactIterator> enumerateBack(Id, Id) override {
101+
return std::make_unique<EmptyIterator>();
102+
}
103+
Interval count(Pid) const override {
104+
return 1;
105+
}
106+
std::unique_ptr<FactIterator>
107+
seek(Pid, folly::ByteRange, std::optional<Fact::Ref>) override {
108+
return std::make_unique<EmptyIterator>();
109+
}
110+
std::unique_ptr<FactIterator> seekWithinSection(
111+
Pid,
112+
folly::ByteRange,
113+
Id,
114+
Id,
115+
std::optional<Fact::Ref>) override {
116+
return std::make_unique<EmptyIterator>();
117+
}
118+
UsetId getOwner(Id) override {
119+
return INVALID_USET;
120+
}
121+
};
122+
66123
struct CacheTest : testing::Test {
67124
template <typename Base, typename F>
68125
void setup(Base&& b, F&& init) {
@@ -78,6 +135,24 @@ struct CacheTest : testing::Test {
78135

79136
void typeById_miss(size_t miss, size_t shards);
80137

138+
TrackingLookup* setupTracking(
139+
size_t capacity = 10 * 1024,
140+
size_t shards = 1,
141+
bool returnEmpty = false) {
142+
auto tracking = std::make_unique<TrackingLookup>();
143+
tracking->returnEmpty = returnEmpty;
144+
auto* trackPtr = tracking.get();
145+
stats = std::make_shared<LookupCache::Stats>();
146+
base = std::move(tracking);
147+
LookupCache::Options opts;
148+
opts.capacity = capacity;
149+
opts.shards = shards;
150+
opts.touched_buffer_size = 128;
151+
cache = std::make_unique<LookupCache>(opts, stats);
152+
lookup = std::make_unique<LookupCache::Anchor>(cache->anchor(trackPtr));
153+
return trackPtr;
154+
}
155+
81156
std::shared_ptr<LookupCache::Stats> stats;
82157
std::unique_ptr<Lookup> base;
83158
std::unique_ptr<LookupCache> cache;
@@ -193,3 +268,190 @@ TEST_F(CacheTest, nested) {
193268
}
194269
});
195270
}
271+
272+
TEST_F(CacheTest, TypeByIdMissRecordsStats) {
273+
auto* trackPtr = setupTracking();
274+
auto type = lookup->typeById(Id::lowest());
275+
EXPECT_EQ(type, Pid::lowest());
276+
EXPECT_EQ(trackPtr->typeByIdCalls, 1);
277+
auto s = stats->read();
278+
EXPECT_EQ(s[LookupCache::Stats::typeById_misses], 1);
279+
EXPECT_EQ(s[LookupCache::Stats::typeById_hits], 0);
280+
}
281+
282+
TEST_F(CacheTest, TypeByIdHitRecordsStats) {
283+
auto* trackPtr = setupTracking();
284+
lookup->typeById(Id::lowest());
285+
auto type = lookup->typeById(Id::lowest());
286+
EXPECT_EQ(type, Pid::lowest());
287+
EXPECT_EQ(trackPtr->typeByIdCalls, 1);
288+
auto s = stats->read();
289+
EXPECT_EQ(s[LookupCache::Stats::typeById_misses], 1);
290+
EXPECT_EQ(s[LookupCache::Stats::typeById_hits], 1);
291+
}
292+
293+
TEST_F(CacheTest, TypeByIdFailureRecordsStats) {
294+
setupTracking(10 * 1024, 1, true);
295+
auto type = lookup->typeById(Id::lowest());
296+
EXPECT_EQ(type, Pid::invalid());
297+
auto s = stats->read();
298+
EXPECT_EQ(s[LookupCache::Stats::typeById_failures], 1);
299+
}
300+
301+
TEST_F(CacheTest, FactByIdMissAndHitRecordsStats) {
302+
auto* trackPtr = setupTracking();
303+
Pid capturedType = Pid::invalid();
304+
bool found = lookup->factById(
305+
Id::lowest(), [&](Pid t, Fact::Clause) { capturedType = t; });
306+
EXPECT_TRUE(found);
307+
EXPECT_EQ(capturedType, Pid::lowest());
308+
EXPECT_EQ(trackPtr->factByIdCalls, 1);
309+
capturedType = Pid::invalid();
310+
found = lookup->factById(
311+
Id::lowest(), [&](Pid t, Fact::Clause) { capturedType = t; });
312+
EXPECT_TRUE(found);
313+
EXPECT_EQ(capturedType, Pid::lowest());
314+
EXPECT_EQ(trackPtr->factByIdCalls, 1);
315+
auto s = stats->read();
316+
EXPECT_EQ(s[LookupCache::Stats::factById_misses], 1);
317+
EXPECT_EQ(s[LookupCache::Stats::factById_hits], 1);
318+
}
319+
320+
TEST_F(CacheTest, FactByIdFailureRecordsStats) {
321+
setupTracking(10 * 1024, 1, true);
322+
bool found = lookup->factById(Id::lowest(), [](Pid, Fact::Clause) {});
323+
EXPECT_FALSE(found);
324+
auto s = stats->read();
325+
EXPECT_EQ(s[LookupCache::Stats::factById_failures], 1);
326+
}
327+
328+
TEST_F(CacheTest, IdByKeyMissAndHitRecordsStats) {
329+
auto* trackPtr = setupTracking();
330+
unsigned char keyData[] = "testkey";
331+
folly::ByteRange key(keyData, 7);
332+
auto id = lookup->idByKey(Pid::lowest(), key);
333+
EXPECT_EQ(id, Id::lowest());
334+
EXPECT_EQ(trackPtr->idByKeyCalls, 1);
335+
id = lookup->idByKey(Pid::lowest(), key);
336+
EXPECT_EQ(id, Id::lowest());
337+
EXPECT_EQ(trackPtr->idByKeyCalls, 1);
338+
auto s = stats->read();
339+
EXPECT_EQ(s[LookupCache::Stats::idByKey_misses], 1);
340+
EXPECT_EQ(s[LookupCache::Stats::idByKey_hits], 1);
341+
}
342+
343+
TEST_F(CacheTest, IdByKeyFailureRecordsStats) {
344+
setupTracking(10 * 1024, 1, true);
345+
unsigned char keyData[] = "testkey";
346+
folly::ByteRange key(keyData, 7);
347+
auto id = lookup->idByKey(Pid::lowest(), key);
348+
EXPECT_EQ(id, Id::invalid());
349+
auto s = stats->read();
350+
EXPECT_EQ(s[LookupCache::Stats::idByKey_failures], 1);
351+
}
352+
353+
TEST_F(CacheTest, ReadAndResetCountersResetsOnlyCounters) {
354+
setupTracking();
355+
lookup->typeById(Id::lowest());
356+
lookup->typeById(Id::lowest());
357+
auto s1 = stats->readAndResetCounters();
358+
EXPECT_EQ(s1[LookupCache::Stats::typeById_misses], 1);
359+
EXPECT_EQ(s1[LookupCache::Stats::typeById_hits], 1);
360+
EXPECT_GT(s1[LookupCache::Stats::factBytes], 0);
361+
EXPECT_EQ(s1[LookupCache::Stats::factCount], 1);
362+
auto s2 = stats->read();
363+
EXPECT_EQ(s2[LookupCache::Stats::typeById_misses], 0);
364+
EXPECT_EQ(s2[LookupCache::Stats::typeById_hits], 0);
365+
EXPECT_GT(s2[LookupCache::Stats::factBytes], 0);
366+
EXPECT_EQ(s2[LookupCache::Stats::factCount], 1);
367+
}
368+
369+
TEST_F(CacheTest, EvictionWhenCapacityExceeded) {
370+
setupTracking(256);
371+
for (size_t i = 0; i < 20; ++i) {
372+
lookup->typeById(Id::lowest() + i);
373+
}
374+
auto s = stats->read();
375+
EXPECT_LE(s[LookupCache::Stats::factBytes], 256);
376+
}
377+
378+
TEST_F(CacheTest, UpgradeFromTypeToFullReplacesEntry) {
379+
auto* trackPtr = setupTracking();
380+
lookup->typeById(Id::lowest());
381+
EXPECT_EQ(trackPtr->typeByIdCalls, 1);
382+
bool found = lookup->factById(Id::lowest(), [](Pid, Fact::Clause) {});
383+
EXPECT_TRUE(found);
384+
EXPECT_EQ(trackPtr->factByIdCalls, 1);
385+
auto s = stats->read();
386+
EXPECT_EQ(s[LookupCache::Stats::factById_deletes], 1);
387+
found = lookup->factById(Id::lowest(), [](Pid, Fact::Clause) {});
388+
EXPECT_TRUE(found);
389+
EXPECT_EQ(trackPtr->factByIdCalls, 1);
390+
}
391+
392+
TEST_F(CacheTest, FIFOReplacementPolicySkipsTouch) {
393+
auto* trackPtr = setupTracking();
394+
auto fifoAnchor =
395+
cache->anchor(trackPtr, LookupCache::Anchor::ReplacementPolicy::FIFO);
396+
fifoAnchor.typeById(Id::lowest());
397+
auto type = fifoAnchor.typeById(Id::lowest());
398+
EXPECT_EQ(type, Pid::lowest());
399+
EXPECT_EQ(trackPtr->typeByIdCalls, 1);
400+
auto s = stats->read();
401+
EXPECT_EQ(s[LookupCache::Stats::typeById_hits], 1);
402+
}
403+
404+
TEST_F(CacheTest, DelegatesEnumerateToBase) {
405+
setupTracking();
406+
auto iter = lookup->enumerate(Id::lowest(), Id::lowest() + 10);
407+
ASSERT_NE(iter, nullptr);
408+
EXPECT_FALSE(bool(iter->get()));
409+
auto iterBack = lookup->enumerateBack(Id::lowest() + 10, Id::lowest());
410+
ASSERT_NE(iterBack, nullptr);
411+
EXPECT_FALSE(bool(iterBack->get()));
412+
unsigned char prefix[] = "test";
413+
auto seekIter = lookup->seek(Pid::lowest(), folly::ByteRange(prefix, 4), {});
414+
ASSERT_NE(seekIter, nullptr);
415+
EXPECT_FALSE(bool(seekIter->get()));
416+
}
417+
418+
TEST_F(CacheTest, BulkStoreInsertsMultipleFacts) {
419+
auto* trackPtr = setupTracking();
420+
unsigned char data[] = "keyvalue";
421+
cache->withBulkStore([&](Store& store) {
422+
for (size_t i = 0; i < 5; ++i) {
423+
Fact::Ref ref;
424+
ref.id = Id::lowest() + i;
425+
ref.type = Pid::lowest();
426+
ref.clause = Fact::Clause::from(folly::ByteRange(data, 8), 3);
427+
store.insert(ref);
428+
}
429+
});
430+
for (size_t i = 0; i < 5; ++i) {
431+
bool found = lookup->factById(Id::lowest() + i, [](Pid, Fact::Clause) {});
432+
EXPECT_TRUE(found);
433+
}
434+
EXPECT_EQ(trackPtr->factByIdCalls, 0);
435+
auto s = stats->read();
436+
EXPECT_EQ(s[LookupCache::Stats::factById_hits], 5);
437+
}
438+
439+
TEST_F(CacheTest, FactTooLargeForCacheIsNotInserted) {
440+
auto* trackPtr = setupTracking(1);
441+
lookup->typeById(Id::lowest());
442+
lookup->typeById(Id::lowest());
443+
EXPECT_EQ(trackPtr->typeByIdCalls, 2);
444+
auto s = stats->read();
445+
EXPECT_EQ(s[LookupCache::Stats::typeById_hits], 0);
446+
EXPECT_EQ(s[LookupCache::Stats::typeById_misses], 2);
447+
}
448+
449+
TEST_F(CacheTest, ZeroShardsUsesDirectTouch) {
450+
setupTracking(10 * 1024, 0);
451+
lookup->typeById(Id::lowest());
452+
auto type = lookup->typeById(Id::lowest());
453+
EXPECT_EQ(type, Pid::lowest());
454+
auto s = stats->read();
455+
EXPECT_EQ(s[LookupCache::Stats::typeById_hits], 1);
456+
EXPECT_EQ(s[LookupCache::Stats::typeById_misses], 1);
457+
}

0 commit comments

Comments
 (0)