|
24 | 24 | #include "dcp/producer.h" |
25 | 25 | #include "dcp/stream.h" |
26 | 26 | #include "evp_store_single_threaded_test.h" |
| 27 | +#include "memory_tracker.h" |
27 | 28 | #include "tasks.h" |
28 | 29 | #include "test_helpers.h" |
29 | 30 | #include "thread_gate.h" |
@@ -144,6 +145,59 @@ TEST_F(StatTest, vbucket_takeover_stats_stream_not_active) { |
144 | 145 | producer->closeStream(/*opaque*/ 0, vbid); |
145 | 146 | } |
146 | 147 |
|
| 148 | +// MB-32589: Check that _hash-dump stats correctly accounts temporary memory. |
| 149 | +TEST_F(StatTest, HashStatsMemUsed) { |
| 150 | + // Enable memory tracking hooks |
| 151 | + MemoryTracker::getInstance(*get_mock_server_api()->alloc_hooks); |
| 152 | + engine->getEpStats().memoryTrackerEnabled.store(true); |
| 153 | + |
| 154 | + ASSERT_TRUE(engine->getEpStats().memoryTrackerEnabled); |
| 155 | + |
| 156 | + // Add some items to VBucket 0 so the stats call has some data to |
| 157 | + // dump. |
| 158 | + store_item(0, makeStoredDocKey("key1"), std::string(100, 'x')); |
| 159 | + store_item(0, makeStoredDocKey("key2"), std::string(100, 'y')); |
| 160 | + |
| 161 | + auto baselineMemory = engine->getEpStats().getPreciseTotalMemoryUsed(); |
| 162 | + |
| 163 | + // Perform the stats call. Should be associated with an engine at this |
| 164 | + // point (as setup by EvpGetStats in the 'real' environment). |
| 165 | + auto oldEngine = ObjectRegistry::getCurrentEngine(); |
| 166 | + ASSERT_TRUE(oldEngine); |
| 167 | + |
| 168 | + cb::const_char_buffer key{"_hash-dump 0"}; |
| 169 | + struct Cookie : public cb::tracing::Traceable { |
| 170 | + int addStats_calls = 0; |
| 171 | + } state; |
| 172 | + |
| 173 | + auto callback = [](const char* key, |
| 174 | + const uint16_t klen, |
| 175 | + const char* val, |
| 176 | + const uint32_t vlen, |
| 177 | + gsl::not_null<const void*> cookie) { |
| 178 | + Cookie& state = |
| 179 | + *reinterpret_cast<Cookie*>(const_cast<void*>(cookie.get())); |
| 180 | + state.addStats_calls++; |
| 181 | + |
| 182 | + // This callback should run in the memcache-context so no engine should |
| 183 | + // be assigned to the current thread. |
| 184 | + EXPECT_FALSE(ObjectRegistry::getCurrentEngine()); |
| 185 | + }; |
| 186 | + |
| 187 | + ASSERT_EQ(ENGINE_SUCCESS, |
| 188 | + engine->getStats(&state, key.data(), key.size(), callback)); |
| 189 | + |
| 190 | + // Sanity check - should have had at least 1 call to ADD_STATS (otherwise |
| 191 | + // the test isn't valid). |
| 192 | + ASSERT_GT(state.addStats_calls, 0); |
| 193 | + |
| 194 | + // Should still be associated with the same engine. |
| 195 | + EXPECT_EQ(oldEngine, ObjectRegistry::getCurrentEngine()); |
| 196 | + |
| 197 | + // Any temporary memory should have been freed by now, and accounted |
| 198 | + // correctly. |
| 199 | + EXPECT_EQ(baselineMemory, engine->getEpStats().getPreciseTotalMemoryUsed()); |
| 200 | +} |
147 | 201 |
|
148 | 202 | TEST_P(DatatypeStatTest, datatypesInitiallyZero) { |
149 | 203 | // Check that the datatype stats initialise to 0 |
|
0 commit comments