blob: c95bf2865018407ec483a454a229803f7d3f1c6d [file] [log] [blame]
Cody Northrop6cca6c22023-02-08 20:23:13 -07001/*
2 ** Copyright 2023, The Android Open Source Project
3 **
4 ** Licensed under the Apache License, Version 2.0 (the "License");
5 ** you may not use this file except in compliance with the License.
6 ** You may obtain a copy of the License at
7 **
8 ** http://www.apache.org/licenses/LICENSE-2.0
9 **
10 ** Unless required by applicable law or agreed to in writing, software
11 ** distributed under the License is distributed on an "AS IS" BASIS,
12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 ** See the License for the specific language governing permissions and
14 ** limitations under the License.
15 */
16
17#include "MultifileBlobCache.h"
18
Cody Northrop027f2422023-11-12 22:51:01 -070019#include <android-base/properties.h>
Cody Northrop6cca6c22023-02-08 20:23:13 -070020#include <android-base/test_utils.h>
21#include <fcntl.h>
22#include <gtest/gtest.h>
23#include <stdio.h>
24
Cody Northrop027f2422023-11-12 22:51:01 -070025#include <fstream>
Cody Northrop6cca6c22023-02-08 20:23:13 -070026#include <memory>
27
Cody Northrop4ee63862024-11-19 22:41:23 -070028#include <com_android_graphics_egl_flags.h>
29
30using namespace com::android::graphics::egl;
31
Cody Northrop027f2422023-11-12 22:51:01 -070032using namespace std::literals;
33
Cody Northrop6cca6c22023-02-08 20:23:13 -070034namespace android {
35
36template <typename T>
37using sp = std::shared_ptr<T>;
38
Cody Northrop5dbcfa72023-03-24 15:34:09 -060039constexpr size_t kMaxKeySize = 2 * 1024;
40constexpr size_t kMaxValueSize = 6 * 1024;
Cody Northrop6cca6c22023-02-08 20:23:13 -070041constexpr size_t kMaxTotalSize = 32 * 1024;
Cody Northropb5267032023-10-24 10:11:21 -060042constexpr size_t kMaxTotalEntries = 64;
Cody Northrop6cca6c22023-02-08 20:23:13 -070043
44class MultifileBlobCacheTest : public ::testing::Test {
45protected:
46 virtual void SetUp() {
Cody Northrop027f2422023-11-12 22:51:01 -070047 clearProperties();
Cody Northrop6cca6c22023-02-08 20:23:13 -070048 mTempFile.reset(new TemporaryFile());
Cody Northrop5dbcfa72023-03-24 15:34:09 -060049 mMBC.reset(new MultifileBlobCache(kMaxKeySize, kMaxValueSize, kMaxTotalSize,
Cody Northropb5267032023-10-24 10:11:21 -060050 kMaxTotalEntries, &mTempFile->path[0]));
Cody Northrop6cca6c22023-02-08 20:23:13 -070051 }
52
Cody Northrop027f2422023-11-12 22:51:01 -070053 virtual void TearDown() {
54 clearProperties();
55 mMBC.reset();
56 }
Cody Northrop6cca6c22023-02-08 20:23:13 -070057
Cody Northrop5f8117a2023-09-26 20:48:59 -060058 int getFileDescriptorCount();
Cody Northrop027f2422023-11-12 22:51:01 -070059 std::vector<std::string> getCacheEntries();
60
61 void clearProperties();
Cody Northrop5f8117a2023-09-26 20:48:59 -060062
Cody Northrop6cca6c22023-02-08 20:23:13 -070063 std::unique_ptr<TemporaryFile> mTempFile;
64 std::unique_ptr<MultifileBlobCache> mMBC;
65};
66
Cody Northrop027f2422023-11-12 22:51:01 -070067void MultifileBlobCacheTest::clearProperties() {
68 // Clear any debug properties used in the tests
69 base::SetProperty("debug.egl.blobcache.cache_version", "");
70 base::WaitForProperty("debug.egl.blobcache.cache_version", "");
71
72 base::SetProperty("debug.egl.blobcache.build_id", "");
73 base::WaitForProperty("debug.egl.blobcache.build_id", "");
74}
75
Cody Northrop6cca6c22023-02-08 20:23:13 -070076TEST_F(MultifileBlobCacheTest, CacheSingleValueSucceeds) {
77 unsigned char buf[4] = {0xee, 0xee, 0xee, 0xee};
78 mMBC->set("abcd", 4, "efgh", 4);
79 ASSERT_EQ(size_t(4), mMBC->get("abcd", 4, buf, 4));
80 ASSERT_EQ('e', buf[0]);
81 ASSERT_EQ('f', buf[1]);
82 ASSERT_EQ('g', buf[2]);
83 ASSERT_EQ('h', buf[3]);
84}
85
86TEST_F(MultifileBlobCacheTest, CacheTwoValuesSucceeds) {
87 unsigned char buf[2] = {0xee, 0xee};
88 mMBC->set("ab", 2, "cd", 2);
89 mMBC->set("ef", 2, "gh", 2);
90 ASSERT_EQ(size_t(2), mMBC->get("ab", 2, buf, 2));
91 ASSERT_EQ('c', buf[0]);
92 ASSERT_EQ('d', buf[1]);
93 ASSERT_EQ(size_t(2), mMBC->get("ef", 2, buf, 2));
94 ASSERT_EQ('g', buf[0]);
95 ASSERT_EQ('h', buf[1]);
96}
97
98TEST_F(MultifileBlobCacheTest, GetSetTwiceSucceeds) {
99 unsigned char buf[2] = {0xee, 0xee};
100 mMBC->set("ab", 2, "cd", 2);
101 ASSERT_EQ(size_t(2), mMBC->get("ab", 2, buf, 2));
102 ASSERT_EQ('c', buf[0]);
103 ASSERT_EQ('d', buf[1]);
104 // Use the same key, but different value
105 mMBC->set("ab", 2, "ef", 2);
106 ASSERT_EQ(size_t(2), mMBC->get("ab", 2, buf, 2));
107 ASSERT_EQ('e', buf[0]);
108 ASSERT_EQ('f', buf[1]);
109}
110
111TEST_F(MultifileBlobCacheTest, GetOnlyWritesInsideBounds) {
112 unsigned char buf[6] = {0xee, 0xee, 0xee, 0xee, 0xee, 0xee};
113 mMBC->set("abcd", 4, "efgh", 4);
114 ASSERT_EQ(size_t(4), mMBC->get("abcd", 4, buf + 1, 4));
115 ASSERT_EQ(0xee, buf[0]);
116 ASSERT_EQ('e', buf[1]);
117 ASSERT_EQ('f', buf[2]);
118 ASSERT_EQ('g', buf[3]);
119 ASSERT_EQ('h', buf[4]);
120 ASSERT_EQ(0xee, buf[5]);
121}
122
123TEST_F(MultifileBlobCacheTest, GetOnlyWritesIfBufferIsLargeEnough) {
124 unsigned char buf[3] = {0xee, 0xee, 0xee};
125 mMBC->set("abcd", 4, "efgh", 4);
126 ASSERT_EQ(size_t(4), mMBC->get("abcd", 4, buf, 3));
127 ASSERT_EQ(0xee, buf[0]);
128 ASSERT_EQ(0xee, buf[1]);
129 ASSERT_EQ(0xee, buf[2]);
130}
131
132TEST_F(MultifileBlobCacheTest, GetDoesntAccessNullBuffer) {
133 mMBC->set("abcd", 4, "efgh", 4);
134 ASSERT_EQ(size_t(4), mMBC->get("abcd", 4, nullptr, 0));
135}
136
137TEST_F(MultifileBlobCacheTest, MultipleSetsCacheLatestValue) {
138 unsigned char buf[4] = {0xee, 0xee, 0xee, 0xee};
139 mMBC->set("abcd", 4, "efgh", 4);
140 mMBC->set("abcd", 4, "ijkl", 4);
141 ASSERT_EQ(size_t(4), mMBC->get("abcd", 4, buf, 4));
142 ASSERT_EQ('i', buf[0]);
143 ASSERT_EQ('j', buf[1]);
144 ASSERT_EQ('k', buf[2]);
145 ASSERT_EQ('l', buf[3]);
146}
147
148TEST_F(MultifileBlobCacheTest, SecondSetKeepsFirstValueIfTooLarge) {
149 unsigned char buf[kMaxValueSize + 1] = {0xee, 0xee, 0xee, 0xee};
150 mMBC->set("abcd", 4, "efgh", 4);
151 mMBC->set("abcd", 4, buf, kMaxValueSize + 1);
152 ASSERT_EQ(size_t(4), mMBC->get("abcd", 4, buf, 4));
153 ASSERT_EQ('e', buf[0]);
154 ASSERT_EQ('f', buf[1]);
155 ASSERT_EQ('g', buf[2]);
156 ASSERT_EQ('h', buf[3]);
157}
158
159TEST_F(MultifileBlobCacheTest, DoesntCacheIfKeyIsTooBig) {
160 char key[kMaxKeySize + 1];
161 unsigned char buf[4] = {0xee, 0xee, 0xee, 0xee};
162 for (int i = 0; i < kMaxKeySize + 1; i++) {
163 key[i] = 'a';
164 }
165 mMBC->set(key, kMaxKeySize + 1, "bbbb", 4);
166 ASSERT_EQ(size_t(0), mMBC->get(key, kMaxKeySize + 1, buf, 4));
167 ASSERT_EQ(0xee, buf[0]);
168 ASSERT_EQ(0xee, buf[1]);
169 ASSERT_EQ(0xee, buf[2]);
170 ASSERT_EQ(0xee, buf[3]);
171}
172
173TEST_F(MultifileBlobCacheTest, DoesntCacheIfValueIsTooBig) {
174 char buf[kMaxValueSize + 1];
175 for (int i = 0; i < kMaxValueSize + 1; i++) {
176 buf[i] = 'b';
177 }
178 mMBC->set("abcd", 4, buf, kMaxValueSize + 1);
179 for (int i = 0; i < kMaxValueSize + 1; i++) {
180 buf[i] = 0xee;
181 }
182 ASSERT_EQ(size_t(0), mMBC->get("abcd", 4, buf, kMaxValueSize + 1));
183 for (int i = 0; i < kMaxValueSize + 1; i++) {
184 SCOPED_TRACE(i);
185 ASSERT_EQ(0xee, buf[i]);
186 }
187}
188
189TEST_F(MultifileBlobCacheTest, CacheMaxKeySizeSucceeds) {
190 char key[kMaxKeySize];
191 unsigned char buf[4] = {0xee, 0xee, 0xee, 0xee};
192 for (int i = 0; i < kMaxKeySize; i++) {
193 key[i] = 'a';
194 }
195 mMBC->set(key, kMaxKeySize, "wxyz", 4);
196 ASSERT_EQ(size_t(4), mMBC->get(key, kMaxKeySize, buf, 4));
197 ASSERT_EQ('w', buf[0]);
198 ASSERT_EQ('x', buf[1]);
199 ASSERT_EQ('y', buf[2]);
200 ASSERT_EQ('z', buf[3]);
201}
202
203TEST_F(MultifileBlobCacheTest, CacheMaxValueSizeSucceeds) {
204 char buf[kMaxValueSize];
205 for (int i = 0; i < kMaxValueSize; i++) {
206 buf[i] = 'b';
207 }
208 mMBC->set("abcd", 4, buf, kMaxValueSize);
209 for (int i = 0; i < kMaxValueSize; i++) {
210 buf[i] = 0xee;
211 }
212 mMBC->get("abcd", 4, buf, kMaxValueSize);
213 for (int i = 0; i < kMaxValueSize; i++) {
214 SCOPED_TRACE(i);
215 ASSERT_EQ('b', buf[i]);
216 }
217}
218
Cody Northropbe163732023-03-22 10:14:26 -0600219TEST_F(MultifileBlobCacheTest, CacheMaxKeyAndValueSizeSucceeds) {
220 char key[kMaxKeySize];
221 for (int i = 0; i < kMaxKeySize; i++) {
222 key[i] = 'a';
223 }
224 char buf[kMaxValueSize];
225 for (int i = 0; i < kMaxValueSize; i++) {
226 buf[i] = 'b';
227 }
228 mMBC->set(key, kMaxKeySize, buf, kMaxValueSize);
229 for (int i = 0; i < kMaxValueSize; i++) {
230 buf[i] = 0xee;
231 }
232 mMBC->get(key, kMaxKeySize, buf, kMaxValueSize);
233 for (int i = 0; i < kMaxValueSize; i++) {
234 SCOPED_TRACE(i);
235 ASSERT_EQ('b', buf[i]);
236 }
237}
238
Cody Northropb5267032023-10-24 10:11:21 -0600239TEST_F(MultifileBlobCacheTest, CacheMaxEntrySucceeds) {
240 // Fill the cache with max entries
241 int i = 0;
242 for (i = 0; i < kMaxTotalEntries; i++) {
243 mMBC->set(std::to_string(i).c_str(), sizeof(i), std::to_string(i).c_str(), sizeof(i));
244 }
245
246 // Ensure it is full
247 ASSERT_EQ(mMBC->getTotalEntries(), kMaxTotalEntries);
248
249 // Add another entry
250 mMBC->set(std::to_string(i).c_str(), sizeof(i), std::to_string(i).c_str(), sizeof(i));
251
252 // Ensure total entries is cut in half + 1
253 ASSERT_EQ(mMBC->getTotalEntries(), kMaxTotalEntries / 2 + 1);
254}
255
Cody Northrop6cca6c22023-02-08 20:23:13 -0700256TEST_F(MultifileBlobCacheTest, CacheMinKeyAndValueSizeSucceeds) {
257 unsigned char buf[1] = {0xee};
258 mMBC->set("x", 1, "y", 1);
259 ASSERT_EQ(size_t(1), mMBC->get("x", 1, buf, 1));
260 ASSERT_EQ('y', buf[0]);
261}
262
Cody Northrop5f8117a2023-09-26 20:48:59 -0600263int MultifileBlobCacheTest::getFileDescriptorCount() {
264 DIR* directory = opendir("/proc/self/fd");
265
266 int fileCount = 0;
267 struct dirent* entry;
268 while ((entry = readdir(directory)) != NULL) {
269 fileCount++;
270 // printf("File: %s\n", entry->d_name);
271 }
272
273 closedir(directory);
274 return fileCount;
275}
276
277TEST_F(MultifileBlobCacheTest, EnsureFileDescriptorsClosed) {
278 // Populate the cache with a bunch of entries
Cody Northropb5267032023-10-24 10:11:21 -0600279 for (int i = 0; i < kMaxTotalEntries; i++) {
Cody Northrop5f8117a2023-09-26 20:48:59 -0600280 // printf("Caching: %i", i);
281
282 // Use the index as the key and value
283 mMBC->set(&i, sizeof(i), &i, sizeof(i));
284
285 int result = 0;
286 ASSERT_EQ(sizeof(i), mMBC->get(&i, sizeof(i), &result, sizeof(result)));
287 ASSERT_EQ(i, result);
288 }
289
290 // Ensure we don't have a bunch of open fds
Cody Northropb5267032023-10-24 10:11:21 -0600291 ASSERT_LT(getFileDescriptorCount(), kMaxTotalEntries / 2);
Cody Northrop5f8117a2023-09-26 20:48:59 -0600292
293 // Close the cache so everything writes out
294 mMBC->finish();
295 mMBC.reset();
296
297 // Now open it again and ensure we still don't have a bunch of open fds
Cody Northropb5267032023-10-24 10:11:21 -0600298 mMBC.reset(new MultifileBlobCache(kMaxKeySize, kMaxValueSize, kMaxTotalSize, kMaxTotalEntries,
299 &mTempFile->path[0]));
Cody Northrop5f8117a2023-09-26 20:48:59 -0600300
301 // Check after initialization
Cody Northropb5267032023-10-24 10:11:21 -0600302 ASSERT_LT(getFileDescriptorCount(), kMaxTotalEntries / 2);
Cody Northrop5f8117a2023-09-26 20:48:59 -0600303
Cody Northropb5267032023-10-24 10:11:21 -0600304 for (int i = 0; i < kMaxTotalEntries; i++) {
Cody Northrop5f8117a2023-09-26 20:48:59 -0600305 int result = 0;
306 ASSERT_EQ(sizeof(i), mMBC->get(&i, sizeof(i), &result, sizeof(result)));
307 ASSERT_EQ(i, result);
308 }
309
310 // And again after we've actually used it
Cody Northropb5267032023-10-24 10:11:21 -0600311 ASSERT_LT(getFileDescriptorCount(), kMaxTotalEntries / 2);
Cody Northrop5f8117a2023-09-26 20:48:59 -0600312}
313
Cody Northrop027f2422023-11-12 22:51:01 -0700314std::vector<std::string> MultifileBlobCacheTest::getCacheEntries() {
315 std::string cachePath = &mTempFile->path[0];
316 std::string multifileDirName = cachePath + ".multifile";
317 std::vector<std::string> cacheEntries;
318
319 struct stat info;
320 if (stat(multifileDirName.c_str(), &info) == 0) {
321 // We have a multifile dir. Skip the status file and return the only entry.
322 DIR* dir;
323 struct dirent* entry;
324 if ((dir = opendir(multifileDirName.c_str())) != nullptr) {
325 while ((entry = readdir(dir)) != nullptr) {
326 if (entry->d_name == "."s || entry->d_name == ".."s) {
327 continue;
328 }
329 if (strcmp(entry->d_name, kMultifileBlobCacheStatusFile) == 0) {
330 continue;
331 }
332 cacheEntries.push_back(multifileDirName + "/" + entry->d_name);
333 }
334 } else {
335 printf("Unable to open %s, error: %s\n", multifileDirName.c_str(),
336 std::strerror(errno));
337 }
338 } else {
339 printf("Unable to stat %s, error: %s\n", multifileDirName.c_str(), std::strerror(errno));
340 }
341
342 return cacheEntries;
343}
344
345TEST_F(MultifileBlobCacheTest, CacheContainsStatus) {
346 struct stat info;
347 std::stringstream statusFile;
348 statusFile << &mTempFile->path[0] << ".multifile/" << kMultifileBlobCacheStatusFile;
349
350 // After INIT, cache should have a status
351 ASSERT_TRUE(stat(statusFile.str().c_str(), &info) == 0);
352
353 // Set one entry
354 mMBC->set("abcd", 4, "efgh", 4);
355
356 // Close the cache so everything writes out
357 mMBC->finish();
358 mMBC.reset();
359
360 // Ensure status lives after closing the cache
361 ASSERT_TRUE(stat(statusFile.str().c_str(), &info) == 0);
362
363 // Open the cache again
364 mMBC.reset(new MultifileBlobCache(kMaxKeySize, kMaxValueSize, kMaxTotalSize, kMaxTotalEntries,
365 &mTempFile->path[0]));
366
367 // Ensure we still have a status
368 ASSERT_TRUE(stat(statusFile.str().c_str(), &info) == 0);
369}
370
371// Verify missing cache status file causes cache the be cleared
372TEST_F(MultifileBlobCacheTest, MissingCacheStatusClears) {
373 // Set one entry
374 mMBC->set("abcd", 4, "efgh", 4);
375
376 // Close the cache so everything writes out
377 mMBC->finish();
378 mMBC.reset();
379
380 // Ensure there is one cache entry
381 ASSERT_EQ(getCacheEntries().size(), 1);
382
383 // Delete the status file
384 std::stringstream statusFile;
385 statusFile << &mTempFile->path[0] << ".multifile/" << kMultifileBlobCacheStatusFile;
386 remove(statusFile.str().c_str());
387
388 // Open the cache again and ensure no cache hits
389 mMBC.reset(new MultifileBlobCache(kMaxKeySize, kMaxValueSize, kMaxTotalSize, kMaxTotalEntries,
390 &mTempFile->path[0]));
391
392 // Ensure we have no entries
393 ASSERT_EQ(getCacheEntries().size(), 0);
394}
395
396// Verify modified cache status file BEGIN causes cache to be cleared
397TEST_F(MultifileBlobCacheTest, ModifiedCacheStatusBeginClears) {
398 // Set one entry
399 mMBC->set("abcd", 4, "efgh", 4);
400
401 // Close the cache so everything writes out
402 mMBC->finish();
403 mMBC.reset();
404
405 // Ensure there is one cache entry
406 ASSERT_EQ(getCacheEntries().size(), 1);
407
408 // Modify the status file
409 std::stringstream statusFile;
410 statusFile << &mTempFile->path[0] << ".multifile/" << kMultifileBlobCacheStatusFile;
411
412 // Stomp on the beginning of the cache file
413 const char* stomp = "BADF00D";
414 std::fstream fs(statusFile.str());
415 fs.seekp(0, std::ios_base::beg);
416 fs.write(stomp, strlen(stomp));
417 fs.flush();
418 fs.close();
419
420 // Open the cache again and ensure no cache hits
421 mMBC.reset(new MultifileBlobCache(kMaxKeySize, kMaxValueSize, kMaxTotalSize, kMaxTotalEntries,
422 &mTempFile->path[0]));
423
424 // Ensure we have no entries
425 ASSERT_EQ(getCacheEntries().size(), 0);
426}
427
428// Verify modified cache status file END causes cache to be cleared
429TEST_F(MultifileBlobCacheTest, ModifiedCacheStatusEndClears) {
430 // Set one entry
431 mMBC->set("abcd", 4, "efgh", 4);
432
433 // Close the cache so everything writes out
434 mMBC->finish();
435 mMBC.reset();
436
437 // Ensure there is one cache entry
438 ASSERT_EQ(getCacheEntries().size(), 1);
439
440 // Modify the status file
441 std::stringstream statusFile;
442 statusFile << &mTempFile->path[0] << ".multifile/" << kMultifileBlobCacheStatusFile;
443
444 // Stomp on the END of the cache status file, modifying its contents
445 const char* stomp = "BADF00D";
446 std::fstream fs(statusFile.str());
447 fs.seekp(-strlen(stomp), std::ios_base::end);
448 fs.write(stomp, strlen(stomp));
449 fs.flush();
450 fs.close();
451
452 // Open the cache again and ensure no cache hits
453 mMBC.reset(new MultifileBlobCache(kMaxKeySize, kMaxValueSize, kMaxTotalSize, kMaxTotalEntries,
454 &mTempFile->path[0]));
455
456 // Ensure we have no entries
457 ASSERT_EQ(getCacheEntries().size(), 0);
458}
459
460// Verify mismatched cacheVersion causes cache to be cleared
461TEST_F(MultifileBlobCacheTest, MismatchedCacheVersionClears) {
462 // Set one entry
463 mMBC->set("abcd", 4, "efgh", 4);
464
Cody Northrop4ee63862024-11-19 22:41:23 -0700465 uint32_t initialCacheVersion = mMBC->getCurrentCacheVersion();
466
Cody Northrop027f2422023-11-12 22:51:01 -0700467 // Close the cache so everything writes out
468 mMBC->finish();
469 mMBC.reset();
470
471 // Ensure there is one cache entry
472 ASSERT_EQ(getCacheEntries().size(), 1);
473
474 // Set a debug cacheVersion
Cody Northrop4ee63862024-11-19 22:41:23 -0700475 std::string newCacheVersion = std::to_string(initialCacheVersion + 1);
Cody Northrop027f2422023-11-12 22:51:01 -0700476 ASSERT_TRUE(base::SetProperty("debug.egl.blobcache.cache_version", newCacheVersion.c_str()));
477 ASSERT_TRUE(
478 base::WaitForProperty("debug.egl.blobcache.cache_version", newCacheVersion.c_str()));
479
480 // Open the cache again and ensure no cache hits
481 mMBC.reset(new MultifileBlobCache(kMaxKeySize, kMaxValueSize, kMaxTotalSize, kMaxTotalEntries,
482 &mTempFile->path[0]));
483
484 // Ensure we have no entries
485 ASSERT_EQ(getCacheEntries().size(), 0);
486}
487
488// Verify mismatched buildId causes cache to be cleared
489TEST_F(MultifileBlobCacheTest, MismatchedBuildIdClears) {
490 // Set one entry
491 mMBC->set("abcd", 4, "efgh", 4);
492
493 // Close the cache so everything writes out
494 mMBC->finish();
495 mMBC.reset();
496
497 // Ensure there is one cache entry
498 ASSERT_EQ(getCacheEntries().size(), 1);
499
500 // Set a debug buildId
501 base::SetProperty("debug.egl.blobcache.build_id", "foo");
502 base::WaitForProperty("debug.egl.blobcache.build_id", "foo");
503
504 // Open the cache again and ensure no cache hits
505 mMBC.reset(new MultifileBlobCache(kMaxKeySize, kMaxValueSize, kMaxTotalSize, kMaxTotalEntries,
506 &mTempFile->path[0]));
507
508 // Ensure we have no entries
509 ASSERT_EQ(getCacheEntries().size(), 0);
510}
511
Cody Northrop6aebcf22024-11-08 15:55:30 -0700512// Ensure cache is correct when a key is reused
513TEST_F(MultifileBlobCacheTest, SameKeyDifferentValues) {
514 if (!flags::multifile_blobcache_advanced_usage()) {
515 GTEST_SKIP() << "Skipping test that requires multifile_blobcache_advanced_usage flag";
516 }
517
518 unsigned char buf[4] = {0xee, 0xee, 0xee, 0xee};
519
520 size_t startingSize = mMBC->getTotalSize();
521
522 // New cache should be empty
523 ASSERT_EQ(startingSize, 0);
524
525 // Set an initial value
526 mMBC->set("ab", 2, "cdef", 4);
527
528 // Grab the new size
529 size_t firstSize = mMBC->getTotalSize();
530
531 // Ensure the size went up
532 // Note: Checking for an exact size is challenging, as the
533 // file size can differ between platforms.
534 ASSERT_GT(firstSize, startingSize);
535
536 // Verify the cache is correct
537 ASSERT_EQ(size_t(4), mMBC->get("ab", 2, buf, 4));
538 ASSERT_EQ('c', buf[0]);
539 ASSERT_EQ('d', buf[1]);
540 ASSERT_EQ('e', buf[2]);
541 ASSERT_EQ('f', buf[3]);
542
543 // Now reuse the key with a smaller value
544 mMBC->set("ab", 2, "gh", 2);
545
546 // Grab the new size
547 size_t secondSize = mMBC->getTotalSize();
548
549 // Ensure it decreased in size
550 ASSERT_LT(secondSize, firstSize);
551
552 // Verify the cache is correct
553 ASSERT_EQ(size_t(2), mMBC->get("ab", 2, buf, 2));
554 ASSERT_EQ('g', buf[0]);
555 ASSERT_EQ('h', buf[1]);
556
557 // Now put back the original value
558 mMBC->set("ab", 2, "cdef", 4);
559
560 // And we should get back a stable size
561 size_t finalSize = mMBC->getTotalSize();
562 ASSERT_EQ(firstSize, finalSize);
563}
564
565// Ensure cache is correct when a key is reused with large value size
566TEST_F(MultifileBlobCacheTest, SameKeyLargeValues) {
567 if (!flags::multifile_blobcache_advanced_usage()) {
568 GTEST_SKIP() << "Skipping test that requires multifile_blobcache_advanced_usage flag";
569 }
570
571 // Create the cache with larger limits to stress test reuse
572 constexpr uint32_t kLocalMaxKeySize = 1 * 1024 * 1024;
573 constexpr uint32_t kLocalMaxValueSize = 4 * 1024 * 1024;
574 constexpr uint32_t kLocalMaxTotalSize = 32 * 1024 * 1024;
575 mMBC.reset(new MultifileBlobCache(kLocalMaxKeySize, kLocalMaxValueSize, kLocalMaxTotalSize,
576 kMaxTotalEntries, &mTempFile->path[0]));
577
578 constexpr uint32_t kLargeValueCount = 8;
579 constexpr uint32_t kLargeValueSize = 64 * 1024;
580
581 // Create a several really large values
582 unsigned char largeValue[kLargeValueCount][kLargeValueSize];
583 for (int i = 0; i < kLargeValueCount; i++) {
584 for (int j = 0; j < kLargeValueSize; j++) {
585 // Fill the value with the index for uniqueness
586 largeValue[i][j] = i;
587 }
588 }
589
590 size_t startingSize = mMBC->getTotalSize();
591
592 // New cache should be empty
593 ASSERT_EQ(startingSize, 0);
594
595 // Cycle through the values and set them all in sequence
596 for (int i = 0; i < kLargeValueCount; i++) {
597 mMBC->set("abcd", 4, largeValue[i], kLargeValueSize);
598 }
599
600 // Ensure we get the last one back
601 unsigned char outBuf[kLargeValueSize];
602 mMBC->get("abcd", 4, outBuf, kLargeValueSize);
603
604 for (int i = 0; i < kLargeValueSize; i++) {
605 // Buffer should contain highest index value
606 ASSERT_EQ(kLargeValueCount - 1, outBuf[i]);
607 }
608}
609
Cody Northrop6cca6c22023-02-08 20:23:13 -0700610} // namespace android