| 2788 | } |
| 2789 | |
| 2790 | void updatePage(PagerEventReasons reason, |
| 2791 | unsigned int level, |
| 2792 | Standalone<VectorRef<LogicalPageID>> pageIDs, |
| 2793 | Reference<ArenaPage> data) override { |
| 2794 | // Get the cache entry for this page, without counting it as a cache hit as we're replacing its contents now |
| 2795 | // or as a cache miss because there is no benefit to the page already being in cache |
| 2796 | // Similarly, this does not count as a point lookup for reason. |
| 2797 | ASSERT(pageIDs.front() != invalidLogicalPageID); |
| 2798 | PageCacheEntry& cacheEntry = pageCache.get(pageIDs.front(), pageIDs.size() * physicalPageSize, true); |
| 2799 | debug_printf("DWALPager(%s) op=write %s cached=%d reading=%d writing=%d\n", |
| 2800 | filename.c_str(), |
| 2801 | toString(pageIDs).c_str(), |
| 2802 | cacheEntry.initialized(), |
| 2803 | cacheEntry.initialized() && cacheEntry.reading(), |
| 2804 | cacheEntry.initialized() && cacheEntry.writing()); |
| 2805 | |
| 2806 | // If the page is still being read then it's not also being written because a write places |
| 2807 | // the new content into readFuture when the write is launched, not when it is completed. |
| 2808 | // Read/write ordering is being enforced so waiting readers will not see the new write. This |
| 2809 | // is necessary for remap erasure to work correctly since the oldest version of a page, located |
| 2810 | // at the original page ID, could have a pending read when that version is expired (after which |
| 2811 | // future reads of the version are not allowed) and the write of the next newest version over top |
| 2812 | // of the original page begins. |
| 2813 | if (!cacheEntry.initialized()) { |
| 2814 | cacheEntry.writeFuture = detach(writePhysicalPage(reason, level, pageIDs, data)); |
| 2815 | } else if (cacheEntry.reading()) { |
| 2816 | // This is very unlikely, maybe impossible in the current pager use cases |
| 2817 | // Wait for the outstanding read to finish, then start the write |
| 2818 | cacheEntry.writeFuture = mapAsync<Void, std::function<Future<Void>(Void)>, Void>( |
| 2819 | success(cacheEntry.readFuture), [=](Void) { return writePhysicalPage(reason, level, pageIDs, data); }); |
| 2820 | } |
| 2821 | // If the page is being written, wait for this write before issuing the new write to ensure the |
| 2822 | // writes happen in the correct order |
| 2823 | else if (cacheEntry.writing()) { |
| 2824 | // This is very unlikely, maybe impossible in the current pager use cases |
| 2825 | // Wait for the previous write to finish, then start new write |
| 2826 | cacheEntry.writeFuture = mapAsync<Void, std::function<Future<Void>(Void)>, Void>( |
| 2827 | cacheEntry.writeFuture, [=](Void) { return writePhysicalPage(reason, level, pageIDs, data); }); |
| 2828 | } else { |
| 2829 | cacheEntry.writeFuture = detach(writePhysicalPage(reason, level, pageIDs, data)); |
| 2830 | } |
| 2831 | |
| 2832 | // Always update the page contents immediately regardless of what happened above. |
| 2833 | cacheEntry.readFuture = data; |
| 2834 | } |
| 2835 | |
| 2836 | Future<LogicalPageID> atomicUpdatePage(PagerEventReasons reason, |
| 2837 | unsigned int level, |
no test coverage detected