|
27 | 27 | * it in the license file.
|
28 | 28 | */
|
29 | 29 |
|
| 30 | +#include <absl/container/node_hash_map.h> |
| 31 | +#include <boost/move/utility_core.hpp> |
| 32 | +#include <boost/none.hpp> |
| 33 | +#include <boost/optional/optional.hpp> |
| 34 | +#include <boost/smart_ptr.hpp> |
| 35 | +#include <cstddef> |
| 36 | +#include <fmt/format.h> |
30 | 37 | #include <string>
|
31 | 38 |
|
| 39 | +#include "mongo/base/string_data.h" |
| 40 | +#include "mongo/bson/timestamp.h" |
| 41 | +#include "mongo/db/client.h" |
32 | 42 | #include "mongo/db/concurrency/locker_noop_service_context_test_fixture.h"
|
33 | 43 | #include "mongo/db/operation_context.h"
|
34 | 44 | #include "mongo/unittest/barrier.h"
|
@@ -803,5 +813,54 @@ TEST_F(ReadThroughCacheAsyncTest, CacheSizeZero) {
|
803 | 813 | }));
|
804 | 814 | }
|
805 | 815 |
|
| 816 | +TEST_F(ReadThroughCacheAsyncTest, EnqueuedRequestLeveragesTheResultOfAnEarlierLookup) { |
| 817 | + MockThreadPool threadPool; |
| 818 | + boost::optional<CausallyConsistentCache::LookupResult> nextToReturn; |
| 819 | + boost::optional<int> valueFetchedByPreviousRequest; |
| 820 | + |
| 821 | + CausallyConsistentCache cache(getServiceContext(), |
| 822 | + threadPool, |
| 823 | + 1, |
| 824 | + [&](OperationContext*, |
| 825 | + const std::string&, |
| 826 | + const CausallyConsistentCache::ValueHandle& cachedValue, |
| 827 | + const Timestamp&) { |
| 828 | + if (valueFetchedByPreviousRequest.has_value()) { |
| 829 | + ASSERT_EQ(cachedValue->counter, |
| 830 | + *valueFetchedByPreviousRequest); |
| 831 | + } else { |
| 832 | + ASSERT(!cachedValue); |
| 833 | + } |
| 834 | + return std::move(*nextToReturn); |
| 835 | + }); |
| 836 | + // Issue two requests, advancing the time in store so that each of them will require a "remote |
| 837 | + // lookup". |
| 838 | + ASSERT(cache.advanceTimeInStore("TestKey", Timestamp(100))); |
| 839 | + auto futureAtTS100 = cache.acquireAsync("TestKey", CacheCausalConsistency::kLatestKnown); |
| 840 | + ASSERT(!futureAtTS100.isReady()); |
| 841 | + |
| 842 | + ASSERT(cache.advanceTimeInStore("TestKey", Timestamp(200))); |
| 843 | + auto futureAtTS200 = cache.acquireAsync("TestKey", CacheCausalConsistency::kLatestKnown); |
| 844 | + ASSERT(!futureAtTS100.isReady()); |
| 845 | + ASSERT(!futureAtTS200.isReady()); |
| 846 | + |
| 847 | + // Serve the first request - and verify that the received result only unblocks one future (with |
| 848 | + // an already stale value). |
| 849 | + nextToReturn.emplace(CachedValue(100), Timestamp(100)); |
| 850 | + valueFetchedByPreviousRequest = boost::none; |
| 851 | + threadPool.runMostRecentTask(); |
| 852 | + ASSERT_EQ(100, futureAtTS100.get()->counter); |
| 853 | + ASSERT(!futureAtTS100.get().isValid()); |
| 854 | + ASSERT(!futureAtTS200.isReady()); |
| 855 | + |
| 856 | + // Serve the second request - and verify that the cache's lookupFn receives the value retrieved |
| 857 | + // by the first one to compute an "incremental remote lookup". |
| 858 | + nextToReturn.emplace(CachedValue(200), Timestamp(200)); |
| 859 | + valueFetchedByPreviousRequest.emplace(100); |
| 860 | + threadPool.runMostRecentTask(); |
| 861 | + ASSERT_EQ(200, futureAtTS200.get()->counter); |
| 862 | + ASSERT(futureAtTS200.get().isValid()); |
| 863 | +} |
| 864 | + |
806 | 865 | } // namespace
|
807 | 866 | } // namespace mongo
|
0 commit comments