cache_ut.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666
  1. #include <library/cpp/cache/cache.h>
  2. #include <library/cpp/cache/thread_safe_cache.h>
  3. #include <library/cpp/testing/unittest/registar.h>
  4. struct TStrokaWeighter {
  5. static size_t Weight(const TString& s) {
  6. return s.size();
  7. }
  8. };
  9. Y_UNIT_TEST_SUITE(TCacheTest) {
  10. Y_UNIT_TEST(LRUListTest) {
  11. typedef TLRUList<int, TString> TListType;
  12. TListType list(2);
  13. TListType::TItem x1(1, "ttt");
  14. list.Insert(&x1);
  15. UNIT_ASSERT_EQUAL(list.GetOldest()->Key, 1);
  16. TListType::TItem x2(2, "yyy");
  17. list.Insert(&x2);
  18. UNIT_ASSERT_EQUAL(list.GetOldest()->Key, 1);
  19. list.Promote(list.GetOldest());
  20. UNIT_ASSERT_EQUAL(list.GetOldest()->Key, 2);
  21. TListType::TItem x3(3, "zzz");
  22. list.Insert(&x3);
  23. UNIT_ASSERT_EQUAL(list.GetOldest()->Key, 1);
  24. }
  25. Y_UNIT_TEST(LRUListWeightedTest) {
  26. typedef TLRUList<int, TString, size_t (*)(const TString&)> TListType;
  27. TListType list(7, [](auto& string) {
  28. return string.size();
  29. });
  30. TListType::TItem x1(1, "ttt");
  31. list.Insert(&x1);
  32. while (list.RemoveIfOverflown()) {
  33. }
  34. UNIT_ASSERT_EQUAL(list.GetOldest()->Key, 1);
  35. TListType::TItem x2(2, "yyy");
  36. list.Insert(&x2);
  37. while (list.RemoveIfOverflown()) {
  38. }
  39. UNIT_ASSERT_EQUAL(list.GetOldest()->Key, 1);
  40. list.Promote(list.GetOldest());
  41. while (list.RemoveIfOverflown()) {
  42. }
  43. UNIT_ASSERT_EQUAL(list.GetOldest()->Key, 2);
  44. TListType::TItem x3(3, "zzz");
  45. list.Insert(&x3);
  46. while (list.RemoveIfOverflown()) {
  47. }
  48. UNIT_ASSERT_EQUAL(list.GetOldest()->Key, 1);
  49. TListType::TItem x4(4, "longlong");
  50. list.Insert(&x4);
  51. while (list.RemoveIfOverflown()) {
  52. }
  53. UNIT_ASSERT_EQUAL(list.GetOldest()->Key, 4);
  54. }
  55. Y_UNIT_TEST(LFUListTest) {
  56. typedef TLFUList<int, TString> TListType;
  57. TListType list(2);
  58. TListType::TItem x1(1, "ttt");
  59. list.Insert(&x1);
  60. UNIT_ASSERT_EQUAL(list.GetLeastFrequentlyUsed()->Key, 1);
  61. TListType::TItem x2(2, "yyy");
  62. list.Insert(&x2);
  63. UNIT_ASSERT_EQUAL(list.GetLeastFrequentlyUsed()->Key, 1);
  64. list.Promote(list.GetLeastFrequentlyUsed());
  65. UNIT_ASSERT_EQUAL(list.GetLeastFrequentlyUsed()->Key, 2);
  66. TListType::TItem x3(3, "zzz");
  67. list.Insert(&x3);
  68. UNIT_ASSERT_EQUAL(list.GetLeastFrequentlyUsed()->Key, 1);
  69. }
  70. Y_UNIT_TEST(LWListTest) {
  71. typedef TLWList<int, TString, size_t, TStrokaWeighter> TListType;
  72. TListType list(2);
  73. TListType::TItem x1(1, "tt");
  74. list.Insert(&x1);
  75. UNIT_ASSERT_EQUAL(list.GetLightest()->Key, 1);
  76. UNIT_ASSERT_EQUAL(list.GetSize(), 1);
  77. TListType::TItem x2(2, "yyyy");
  78. list.Insert(&x2);
  79. UNIT_ASSERT_EQUAL(list.GetLightest()->Key, 1);
  80. UNIT_ASSERT_EQUAL(list.GetSize(), 2);
  81. TListType::TItem x3(3, "z");
  82. list.Insert(&x3);
  83. UNIT_ASSERT_EQUAL(list.GetLightest()->Key, 1);
  84. UNIT_ASSERT_EQUAL(list.GetSize(), 2);
  85. TListType::TItem x4(4, "xxxxxx");
  86. list.Insert(&x4);
  87. UNIT_ASSERT_EQUAL(list.GetLightest()->Key, 2);
  88. UNIT_ASSERT_EQUAL(list.GetSize(), 2);
  89. list.Erase(&x2);
  90. UNIT_ASSERT_EQUAL(list.GetLightest()->Key, 4);
  91. UNIT_ASSERT_EQUAL(list.GetSize(), 1);
  92. }
  93. Y_UNIT_TEST(SimpleTest) {
  94. typedef TLRUCache<int, TString> TCache;
  95. TCache s(2); // size 2
  96. s.Insert(1, "abcd");
  97. UNIT_ASSERT(s.Find(1) != s.End());
  98. UNIT_ASSERT_EQUAL(*s.Find(1), "abcd");
  99. s.Insert(2, "defg");
  100. UNIT_ASSERT(s.GetOldest() == "abcd");
  101. s.Insert(3, "hjkl");
  102. UNIT_ASSERT(s.GetOldest() == "defg");
  103. // key 1 will be deleted
  104. UNIT_ASSERT(s.Find(1) == s.End());
  105. UNIT_ASSERT(s.Find(2) != s.End());
  106. UNIT_ASSERT(*s.Find(2) == "defg");
  107. UNIT_ASSERT(s.Find(3) != s.End());
  108. UNIT_ASSERT(*s.Find(3) == "hjkl");
  109. UNIT_ASSERT(!s.Insert(3, "abcd"));
  110. UNIT_ASSERT(*s.Find(3) == "hjkl");
  111. s.Update(3, "abcd");
  112. UNIT_ASSERT(*s.Find(3) == "abcd");
  113. TCache::TIterator it = s.Find(3);
  114. s.Erase(it);
  115. UNIT_ASSERT(s.Find(3) == s.End());
  116. }
  117. Y_UNIT_TEST(LRUWithCustomSizeProviderTest) {
  118. typedef TLRUCache<int, TString, TNoopDelete, size_t(*)(const TString&)> TCache;
  119. TCache s(10, false, [](auto& string) { return string.size(); }); // size 10
  120. s.Insert(1, "abcd");
  121. UNIT_ASSERT(s.Find(1) != s.End());
  122. UNIT_ASSERT_EQUAL(*s.Find(1), "abcd");
  123. s.Insert(2, "defg");
  124. UNIT_ASSERT(s.GetOldest() == "abcd");
  125. s.Insert(3, "2c");
  126. UNIT_ASSERT(s.GetOldest() == "abcd");
  127. s.Insert(4, "hjkl");
  128. UNIT_ASSERT(s.GetOldest() == "defg");
  129. // key 1 will be deleted
  130. UNIT_ASSERT(s.Find(1) == s.End());
  131. UNIT_ASSERT(s.Find(2) != s.End());
  132. UNIT_ASSERT(*s.Find(2) == "defg");
  133. UNIT_ASSERT(s.Find(3) != s.End());
  134. UNIT_ASSERT(*s.Find(3) == "2c");
  135. UNIT_ASSERT(s.Find(4) != s.End());
  136. UNIT_ASSERT(*s.Find(4) == "hjkl");
  137. UNIT_ASSERT(!s.Insert(3, "abcd"));
  138. UNIT_ASSERT(*s.Find(3) == "2c");
  139. s.Update(3, "abcd");
  140. UNIT_ASSERT(*s.Find(3) == "abcd");
  141. TCache::TIterator it = s.Find(3);
  142. s.Erase(it);
  143. UNIT_ASSERT(s.Find(3) == s.End());
  144. }
  145. Y_UNIT_TEST(LRUSetMaxSizeTest) {
  146. typedef TLRUCache<int, TString> TCache;
  147. TCache s(2); // size 2
  148. s.Insert(1, "abcd");
  149. s.Insert(2, "efgh");
  150. s.Insert(3, "ijkl");
  151. UNIT_ASSERT(s.GetOldest() == "efgh");
  152. UNIT_ASSERT(s.Find(1) == s.End());
  153. UNIT_ASSERT(s.Find(2) != s.End());
  154. UNIT_ASSERT(s.Find(3) != s.End());
  155. // Increasing size should not change anything
  156. s.SetMaxSize(3);
  157. UNIT_ASSERT(s.GetOldest() == "efgh");
  158. UNIT_ASSERT(s.Find(1) == s.End());
  159. UNIT_ASSERT(s.Find(2) != s.End());
  160. UNIT_ASSERT(s.Find(3) != s.End());
  161. // And we should be able to add fit more entries
  162. s.Insert(4, "mnop");
  163. s.Insert(5, "qrst");
  164. UNIT_ASSERT(s.GetOldest() == "ijkl");
  165. UNIT_ASSERT(s.Find(1) == s.End());
  166. UNIT_ASSERT(s.Find(2) == s.End());
  167. UNIT_ASSERT(s.Find(3) != s.End());
  168. UNIT_ASSERT(s.Find(4) != s.End());
  169. UNIT_ASSERT(s.Find(5) != s.End());
  170. // Decreasing size should remove oldest entries
  171. s.SetMaxSize(2);
  172. UNIT_ASSERT(s.GetOldest() == "mnop");
  173. UNIT_ASSERT(s.Find(1) == s.End());
  174. UNIT_ASSERT(s.Find(2) == s.End());
  175. UNIT_ASSERT(s.Find(3) == s.End());
  176. UNIT_ASSERT(s.Find(4) != s.End());
  177. UNIT_ASSERT(s.Find(5) != s.End());
  178. // Ano no more entries will fit
  179. s.Insert(6, "uvwx");
  180. UNIT_ASSERT(s.GetOldest() == "qrst");
  181. UNIT_ASSERT(s.Find(1) == s.End());
  182. UNIT_ASSERT(s.Find(2) == s.End());
  183. UNIT_ASSERT(s.Find(3) == s.End());
  184. UNIT_ASSERT(s.Find(4) == s.End());
  185. UNIT_ASSERT(s.Find(5) != s.End());
  186. UNIT_ASSERT(s.Find(6) != s.End());
  187. }
  188. Y_UNIT_TEST(LWSetMaxSizeTest) {
  189. typedef TLWCache<int, TString, size_t, TStrokaWeighter> TCache;
  190. TCache s(2); // size 2
  191. s.Insert(1, "a");
  192. s.Insert(2, "aa");
  193. s.Insert(3, "aaa");
  194. UNIT_ASSERT(s.GetLightest() == "aa");
  195. UNIT_ASSERT(s.Find(1) == s.End());
  196. UNIT_ASSERT(s.Find(2) != s.End());
  197. UNIT_ASSERT(s.Find(3) != s.End());
  198. // Increasing size should not change anything
  199. s.SetMaxSize(3);
  200. UNIT_ASSERT(s.GetLightest() == "aa");
  201. UNIT_ASSERT(s.Find(1) == s.End());
  202. UNIT_ASSERT(s.Find(2) != s.End());
  203. UNIT_ASSERT(s.Find(3) != s.End());
  204. // And we should be able to add fit more entries
  205. s.Insert(4, "aaaa");
  206. s.Insert(5, "aaaaa");
  207. UNIT_ASSERT(s.GetLightest() == "aaa");
  208. UNIT_ASSERT(s.Find(1) == s.End());
  209. UNIT_ASSERT(s.Find(2) == s.End());
  210. UNIT_ASSERT(s.Find(3) != s.End());
  211. UNIT_ASSERT(s.Find(4) != s.End());
  212. UNIT_ASSERT(s.Find(5) != s.End());
  213. // Decreasing size should remove oldest entries
  214. s.SetMaxSize(2);
  215. UNIT_ASSERT(s.GetLightest() == "aaaa");
  216. UNIT_ASSERT(s.Find(1) == s.End());
  217. UNIT_ASSERT(s.Find(2) == s.End());
  218. UNIT_ASSERT(s.Find(3) == s.End());
  219. UNIT_ASSERT(s.Find(4) != s.End());
  220. UNIT_ASSERT(s.Find(5) != s.End());
  221. // Ano no more entries will fit
  222. s.Insert(6, "aaaaaa");
  223. UNIT_ASSERT(s.GetLightest() == "aaaaa");
  224. UNIT_ASSERT(s.Find(1) == s.End());
  225. UNIT_ASSERT(s.Find(2) == s.End());
  226. UNIT_ASSERT(s.Find(3) == s.End());
  227. UNIT_ASSERT(s.Find(4) == s.End());
  228. UNIT_ASSERT(s.Find(5) != s.End());
  229. UNIT_ASSERT(s.Find(6) != s.End());
  230. }
  231. Y_UNIT_TEST(LFUSetMaxSizeTest) {
  232. typedef TLFUCache<int, TString> TCache;
  233. TCache s(2); // size 2
  234. s.Insert(1, "abcd");
  235. s.Insert(2, "efgh");
  236. s.Insert(3, "ijkl");
  237. UNIT_ASSERT(s.Find(1) == s.End());
  238. UNIT_ASSERT(s.Find(2) != s.End());
  239. UNIT_ASSERT(s.Find(3) != s.End());
  240. // Increasing size should not change anything
  241. s.SetMaxSize(3);
  242. UNIT_ASSERT(s.Find(1) == s.End());
  243. UNIT_ASSERT(s.Find(2) != s.End());
  244. UNIT_ASSERT(s.Find(3) != s.End());
  245. // And we should be able to add fit more entries
  246. s.Insert(4, "mnop");
  247. s.Insert(5, "qrst");
  248. UNIT_ASSERT(s.Find(1) == s.End());
  249. UNIT_ASSERT(s.Find(2) == s.End());
  250. UNIT_ASSERT(s.Find(3) != s.End());
  251. UNIT_ASSERT(s.Find(4) != s.End());
  252. UNIT_ASSERT(s.Find(5) != s.End());
  253. // Decreasing size should remove oldest entries
  254. s.SetMaxSize(2);
  255. UNIT_ASSERT(s.Find(1) == s.End());
  256. UNIT_ASSERT(s.Find(2) == s.End());
  257. UNIT_ASSERT(s.Find(3) != s.End());
  258. UNIT_ASSERT(s.Find(4) == s.End());
  259. UNIT_ASSERT(s.Find(5) != s.End());
  260. // Ano no more entries will fit
  261. s.Insert(6, "uvwx");
  262. UNIT_ASSERT(s.Find(1) == s.End());
  263. UNIT_ASSERT(s.Find(2) == s.End());
  264. UNIT_ASSERT(s.Find(3) != s.End());
  265. UNIT_ASSERT(s.Find(4) == s.End());
  266. UNIT_ASSERT(s.Find(5) == s.End());
  267. UNIT_ASSERT(s.Find(6) != s.End());
  268. }
  269. Y_UNIT_TEST(MultiCacheTest) {
  270. typedef TLRUCache<int, TString> TCache;
  271. TCache s(3, true);
  272. UNIT_ASSERT(s.Insert(1, "abcd"));
  273. UNIT_ASSERT(s.Insert(1, "bcde"));
  274. UNIT_ASSERT(s.Insert(2, "fghi"));
  275. UNIT_ASSERT(s.Insert(2, "ghij"));
  276. // (1, "abcd") will be deleted
  277. UNIT_ASSERT(*s.Find(1) == "bcde");
  278. // (1, "bcde") will be promoted
  279. UNIT_ASSERT(*s.FindOldest() == "fghi");
  280. }
  281. struct TMyDelete {
  282. static int count;
  283. template <typename T>
  284. static void Destroy(const T&) {
  285. ++count;
  286. }
  287. };
  288. int TMyDelete::count = 0;
  289. Y_UNIT_TEST(DeleterTest) {
  290. typedef TLRUCache<int, TString, TMyDelete> TCache;
  291. TCache s(2);
  292. s.Insert(1, "123");
  293. s.Insert(2, "456");
  294. s.Insert(3, "789");
  295. UNIT_ASSERT(TMyDelete::count == 1);
  296. TCache::TIterator it = s.Find(2);
  297. UNIT_ASSERT(it != s.End());
  298. s.Erase(it);
  299. UNIT_ASSERT(TMyDelete::count == 2);
  300. }
  301. Y_UNIT_TEST(PromoteOnFind) {
  302. typedef TLRUCache<int, TString> TCache;
  303. TCache s(2);
  304. s.Insert(1, "123");
  305. s.Insert(2, "456");
  306. UNIT_ASSERT(s.Find(1) != s.End());
  307. s.Insert(3, "789");
  308. UNIT_ASSERT(s.Find(1) != s.End()); // Key 2 should have been deleted
  309. }
  310. class TMoveOnlyInt {
  311. public:
  312. ui32 Value = 0;
  313. explicit TMoveOnlyInt(ui32 value = 0) : Value(value) {}
  314. TMoveOnlyInt(TMoveOnlyInt&&) = default;
  315. TMoveOnlyInt& operator=(TMoveOnlyInt&&) = default;
  316. TMoveOnlyInt(const TMoveOnlyInt&) = delete;
  317. TMoveOnlyInt& operator=(const TMoveOnlyInt&) = delete;
  318. bool operator==(const TMoveOnlyInt& rhs) const {
  319. return Value == rhs.Value;
  320. }
  321. explicit operator size_t() const {
  322. return Value;
  323. }
  324. };
  325. Y_UNIT_TEST(MoveOnlySimpleTest) {
  326. typedef TLRUCache<TMoveOnlyInt, TMoveOnlyInt> TCache;
  327. TCache s(2); // size 2
  328. s.Insert(TMoveOnlyInt(1), TMoveOnlyInt(0x11111111));
  329. TMoveOnlyInt lookup1(1), lookup2(2), lookup3(3);
  330. UNIT_ASSERT(s.Find(lookup1) != s.End());
  331. UNIT_ASSERT_EQUAL(s.Find(lookup1)->Value, 0x11111111);
  332. s.Insert(TMoveOnlyInt(2), TMoveOnlyInt(0x22222222));
  333. UNIT_ASSERT(s.GetOldest().Value == 0x11111111);
  334. s.Insert(TMoveOnlyInt(3), TMoveOnlyInt(0x33333333));
  335. UNIT_ASSERT(s.GetOldest().Value == 0x22222222);
  336. // key 1 will be deleted
  337. UNIT_ASSERT(s.Find(lookup1) == s.End());
  338. UNIT_ASSERT(s.Find(lookup2) != s.End());
  339. UNIT_ASSERT(s.Find(lookup2)->Value == 0x22222222);
  340. UNIT_ASSERT(s.Find(lookup3) != s.End());
  341. UNIT_ASSERT(s.Find(lookup3)->Value == 0x33333333);
  342. UNIT_ASSERT(!s.Insert(TMoveOnlyInt(3), TMoveOnlyInt(0x11111111)));
  343. UNIT_ASSERT(s.Find(lookup3)->Value == 0x33333333);
  344. s.Update(TMoveOnlyInt(3), TMoveOnlyInt(0x11111111));
  345. UNIT_ASSERT(s.Find(lookup3)->Value == 0x11111111);
  346. TCache::TIterator it = s.Find(lookup3);
  347. s.Erase(it);
  348. UNIT_ASSERT(s.Find(lookup3) == s.End());
  349. }
  350. }
  351. Y_UNIT_TEST_SUITE(TThreadSafeCacheTest) {
  352. typedef TThreadSafeCache<ui32, TString, ui32> TCache;
  353. const char* VALS[] = {"abcd", "defg", "hjkl"};
  354. class TCallbacks: public TCache::ICallbacks {
  355. public:
  356. TKey GetKey(ui32 i) const override {
  357. return i;
  358. }
  359. TValue* CreateObject(ui32 i) const override {
  360. Creations++;
  361. return new TString(VALS[i]);
  362. }
  363. mutable i32 Creations = 0;
  364. };
  365. Y_UNIT_TEST(SimpleTest) {
  366. for (ui32 i = 0; i < Y_ARRAY_SIZE(VALS); ++i) {
  367. const TString data = *TCache::Get<TCallbacks>(i);
  368. UNIT_ASSERT(data == VALS[i]);
  369. }
  370. }
  371. Y_UNIT_TEST(InsertUpdateTest) {
  372. TCallbacks callbacks;
  373. TCache cache(callbacks, 10);
  374. cache.Insert(2, MakeAtomicShared<TString>("hj"));
  375. TAtomicSharedPtr<TString> item = cache.Get(2);
  376. UNIT_ASSERT(callbacks.Creations == 0);
  377. UNIT_ASSERT(*item == "hj");
  378. cache.Insert(2, MakeAtomicShared<TString>("hjk"));
  379. item = cache.Get(2);
  380. UNIT_ASSERT(callbacks.Creations == 0);
  381. UNIT_ASSERT(*item == "hj");
  382. cache.Update(2, MakeAtomicShared<TString>("hjk"));
  383. item = cache.Get(2);
  384. UNIT_ASSERT(callbacks.Creations == 0);
  385. UNIT_ASSERT(*item == "hjk");
  386. }
  387. }
  388. Y_UNIT_TEST_SUITE(TThreadSafeCacheUnsafeTest) {
  389. typedef TThreadSafeCache<ui32, TString, ui32> TCache;
  390. const char* VALS[] = {"abcd", "defg", "hjkl"};
  391. const ui32 FAILED_IDX = 1;
  392. class TCallbacks: public TCache::ICallbacks {
  393. public:
  394. TKey GetKey(ui32 i) const override {
  395. return i;
  396. }
  397. TValue* CreateObject(ui32 i) const override {
  398. if (i == FAILED_IDX) {
  399. return nullptr;
  400. }
  401. return new TString(VALS[i]);
  402. }
  403. };
  404. Y_UNIT_TEST(SimpleTest) {
  405. TCallbacks callbacks;
  406. TCache cache(callbacks, Y_ARRAY_SIZE(VALS));
  407. for (ui32 i = 0; i < Y_ARRAY_SIZE(VALS); ++i) {
  408. const TString* data = cache.GetUnsafe(i).Get();
  409. if (i == FAILED_IDX) {
  410. UNIT_ASSERT(data == nullptr);
  411. } else {
  412. UNIT_ASSERT(*data == VALS[i]);
  413. }
  414. }
  415. }
  416. }
  417. Y_UNIT_TEST_SUITE(TThreadSafeLRUCacheTest) {
  418. typedef TThreadSafeLRUCache<size_t, TString, size_t> TCache;
  419. TVector<TString> Values = {"zero", "one", "two", "three", "four"};
  420. class TCallbacks: public TCache::ICallbacks {
  421. public:
  422. TKey GetKey(size_t i) const override {
  423. return i;
  424. }
  425. TValue* CreateObject(size_t i) const override {
  426. UNIT_ASSERT(i < Values.size());
  427. Creations++;
  428. return new TString(Values[i]);
  429. }
  430. mutable size_t Creations = 0;
  431. };
  432. Y_UNIT_TEST(SimpleTest) {
  433. for (size_t i = 0; i < Values.size(); ++i) {
  434. const TString data = *TCache::Get<TCallbacks>(i);
  435. UNIT_ASSERT(data == Values[i]);
  436. }
  437. }
  438. Y_UNIT_TEST(InsertUpdateTest) {
  439. TCallbacks callbacks;
  440. TCache cache(callbacks, 10);
  441. cache.Insert(2, MakeAtomicShared<TString>("hj"));
  442. TAtomicSharedPtr<TString> item = cache.Get(2);
  443. UNIT_ASSERT(callbacks.Creations == 0);
  444. UNIT_ASSERT(*item == "hj");
  445. cache.Insert(2, MakeAtomicShared<TString>("hjk"));
  446. item = cache.Get(2);
  447. UNIT_ASSERT(callbacks.Creations == 0);
  448. UNIT_ASSERT(*item == "hj");
  449. cache.Update(2, MakeAtomicShared<TString>("hjk"));
  450. item = cache.Get(2);
  451. UNIT_ASSERT(callbacks.Creations == 0);
  452. UNIT_ASSERT(*item == "hjk");
  453. }
  454. Y_UNIT_TEST(LRUTest) {
  455. TCallbacks callbacks;
  456. TCache cache(callbacks, 3);
  457. UNIT_ASSERT_EQUAL(cache.GetMaxSize(), 3);
  458. for (size_t i = 0; i < Values.size(); ++i) {
  459. TAtomicSharedPtr<TString> item = cache.Get(i);
  460. UNIT_ASSERT(*item == Values[i]);
  461. }
  462. UNIT_ASSERT(callbacks.Creations == Values.size());
  463. size_t expectedCreations = Values.size();
  464. TAtomicSharedPtr<TString> item;
  465. item = cache.Get(4);
  466. UNIT_ASSERT_EQUAL(callbacks.Creations, expectedCreations);
  467. UNIT_ASSERT(*item == "four");
  468. item = cache.Get(2);
  469. UNIT_ASSERT_EQUAL(callbacks.Creations, expectedCreations);
  470. UNIT_ASSERT(*item == "two");
  471. item = cache.Get(0);
  472. expectedCreations++;
  473. UNIT_ASSERT_EQUAL(callbacks.Creations, expectedCreations);
  474. UNIT_ASSERT(*item == "zero");
  475. UNIT_ASSERT(cache.Contains(1) == false);
  476. UNIT_ASSERT(cache.Contains(3) == false);
  477. UNIT_ASSERT(cache.Contains(4));
  478. UNIT_ASSERT(cache.Contains(2));
  479. UNIT_ASSERT(cache.Contains(0));
  480. item = cache.Get(3);
  481. expectedCreations++;
  482. UNIT_ASSERT_EQUAL(callbacks.Creations, expectedCreations);
  483. UNIT_ASSERT(*item == "three");
  484. item = cache.Get(2);
  485. UNIT_ASSERT_EQUAL(callbacks.Creations, expectedCreations);
  486. UNIT_ASSERT(*item == "two");
  487. item = cache.Get(0);
  488. UNIT_ASSERT_EQUAL(callbacks.Creations, expectedCreations);
  489. UNIT_ASSERT(*item == "zero");
  490. item = cache.Get(1);
  491. expectedCreations++;
  492. UNIT_ASSERT_EQUAL(callbacks.Creations, expectedCreations);
  493. UNIT_ASSERT(*item == "one");
  494. item = cache.Get(2);
  495. UNIT_ASSERT_EQUAL(callbacks.Creations, expectedCreations);
  496. UNIT_ASSERT(*item == "two");
  497. item = cache.Get(4);
  498. expectedCreations++;
  499. UNIT_ASSERT_EQUAL(callbacks.Creations, expectedCreations);
  500. UNIT_ASSERT(*item == "four");
  501. }
  502. Y_UNIT_TEST(ChangeMaxSizeTest) {
  503. TCallbacks callbacks;
  504. TCache cache(callbacks, 3);
  505. UNIT_ASSERT_EQUAL(cache.GetMaxSize(), 3);
  506. for (size_t i = 0; i < Values.size(); ++i) {
  507. TAtomicSharedPtr<TString> item = cache.Get(i);
  508. UNIT_ASSERT(*item == Values[i]);
  509. }
  510. size_t expectedCreations = Values.size();
  511. TAtomicSharedPtr<TString> item;
  512. item = cache.Get(4);
  513. UNIT_ASSERT_EQUAL(callbacks.Creations, expectedCreations);
  514. UNIT_ASSERT(*item == "four");
  515. item = cache.Get(3);
  516. UNIT_ASSERT_EQUAL(callbacks.Creations, expectedCreations);
  517. UNIT_ASSERT(*item == "three");
  518. item = cache.Get(2);
  519. UNIT_ASSERT_EQUAL(callbacks.Creations, expectedCreations);
  520. UNIT_ASSERT(*item == "two");
  521. item = cache.Get(1);
  522. expectedCreations++;
  523. UNIT_ASSERT_EQUAL(callbacks.Creations, expectedCreations);
  524. UNIT_ASSERT(*item == "one");
  525. cache.SetMaxSize(4);
  526. item = cache.Get(0);
  527. expectedCreations++;
  528. UNIT_ASSERT_EQUAL(callbacks.Creations, expectedCreations);
  529. UNIT_ASSERT(*item == "zero");
  530. item = cache.Get(4);
  531. expectedCreations++;
  532. UNIT_ASSERT_EQUAL(callbacks.Creations, expectedCreations);
  533. UNIT_ASSERT(*item == "four");
  534. item = cache.Get(3);
  535. expectedCreations++;
  536. UNIT_ASSERT_EQUAL(callbacks.Creations, expectedCreations);
  537. UNIT_ASSERT(*item == "three");
  538. UNIT_ASSERT(cache.Contains(2) == false);
  539. cache.SetMaxSize(2);
  540. UNIT_ASSERT(cache.Contains(3));
  541. UNIT_ASSERT(cache.Contains(4));
  542. UNIT_ASSERT(cache.Contains(2) == false);
  543. UNIT_ASSERT(cache.Contains(1) == false);
  544. UNIT_ASSERT(cache.Contains(0) == false);
  545. item = cache.Get(0);
  546. expectedCreations++;
  547. UNIT_ASSERT_EQUAL(callbacks.Creations, expectedCreations);
  548. UNIT_ASSERT(*item == "zero");
  549. UNIT_ASSERT(cache.Contains(4) == false);
  550. UNIT_ASSERT(cache.Contains(3));
  551. UNIT_ASSERT(cache.Contains(0));
  552. }
  553. }