/* * Copyright (c) 2020 Red Hat, Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. * * $Id: //eng/vdo-releases/aluminum/src/c++/vdo/base/vdoPageCache.h#7 $ */ #ifndef VDO_PAGE_CACHE_H #define VDO_PAGE_CACHE_H #include "adminState.h" #include "atomic.h" #include "completion.h" #include "types.h" #include "waitQueue.h" /** * Structure describing page meta data (defined internally). **/ typedef struct pageInfo PageInfo; /** * Structure describing entire page cache. * (Unfortunately the name "PageCache" is already taken by Albireo.) **/ typedef struct vdoPageCache VDOPageCache; /** * Generation counter for page references. **/ typedef uint32_t VDOPageGeneration; /** * Page-state count statistics sub-structure. **/ typedef struct { /* free pages */ Atomic64 freePages; /* clean (resident) pages */ Atomic64 cleanPages; /* dirty pages per era */ Atomic64 dirtyPages; /* pages incoming */ Atomic64 incomingPages; /* pages outgoing */ Atomic64 outgoingPages; /* pages in failed state */ Atomic64 failedPages; } AtomicPageStateCounts; /** * Statistics and debugging fields for the page cache. */ typedef struct { /* counts of how many pages are in each state */ AtomicPageStateCounts counts; /* how many times free page not available */ Atomic64 cachePressure; /* number of getVDOPageAsync() for read */ Atomic64 readCount; /* number or getVDOPageAsync() for write */ Atomic64 writeCount; /* number of times pages failed to read */ Atomic64 failedReads; /* number of times pages failed to write */ Atomic64 failedWrites; /* number of gets that are reclaimed */ Atomic64 reclaimed; /* number of gets for outgoing pages */ Atomic64 readOutgoing; /* number of gets that were already there */ Atomic64 foundInCache; /* number of gets requiring discard */ Atomic64 discardRequired; /* number of gets enqueued for their page */ Atomic64 waitForPage; /* number of gets that have to fetch */ Atomic64 fetchRequired; /* number of page fetches */ Atomic64 pagesLoaded; /* number of page saves */ Atomic64 pagesSaved; /* number of flushes initiated */ Atomic64 flushCount; } AtomicPageCacheStatistics; /** * Signature for a function to call when a page is read into the cache. * *

If specified, this function is called when a page is fetched from disk. * * @param rawPage The raw memory of the freshly-fetched page * @param pbn The absolute physical block number of the page * @param zone The block map zone to which the cache belongs * @param pageContext A pointer to client-specific data for the new page * * @return VDO_SUCCESS on success or VDO_BAD_PAGE if the page is incorrectly * formatted **/ typedef int VDOPageReadFunction(void *rawPage, PhysicalBlockNumber pbn, BlockMapZone *zone, void *pageContext); /** * Signature for a function to call when a page is written from the cache. * *

If specified, this function is called when a page is written to disk. * * @param rawPage The raw memory of the freshly-written page * @param zone The block map zone to which the cache belongs * @param pageContext A pointer to client-specific data for the new page * * @return whether the page needs to be rewritten **/ typedef bool VDOPageWriteFunction(void *rawPage, BlockMapZone *zone, void *pageContext); /** * Construct a PageCache. * * @param [in] layer The physical layer to read and write * @param [in] pageCount The number of cache pages to hold * @param [in] readHook The function to be called when a page is read * into the cache * @param [in] writeHook The function to be called after a page is * written from the cache * @param [in] pageContextSize The size of the per-page context that will be * passed to the read and write hooks * @param [in] maximumAge The number of journal blocks before a dirtied * page is considered old and must be written * out * @param [in] zone The block map zone which owns this cache * @param [out] cachePtr A pointer to hold the cache * * @return a success or error code **/ int makeVDOPageCache(PhysicalLayer *layer, PageCount pageCount, VDOPageReadFunction *readHook, VDOPageWriteFunction *writeHook, size_t pageContextSize, BlockCount maximumAge, BlockMapZone *zone, VDOPageCache **cachePtr) __attribute__((warn_unused_result)); /** * Free the page cache structure and null out the reference to it. * * @param cachePtr a pointer to the cache to free **/ void freeVDOPageCache(VDOPageCache **cachePtr); /** * Set the initial dirty period for a page cache. * * @param cache The cache * @param period The initial dirty period to set **/ void setVDOPageCacheInitialPeriod(VDOPageCache *cache, SequenceNumber period); /** * Switch the page cache into or out of read-only rebuild mode. * * @param cache The cache * @param rebuilding true if the cache should be put into * read-only rebuild mode, false otherwise **/ void setVDOPageCacheRebuildMode(VDOPageCache *cache, bool rebuilding); /** * Check whether a page cache is active (i.e. has any active lookups, * outstanding I/O, or pending I/O). * * @param cache The cache to check * * @return true if the cache is active **/ bool isPageCacheActive(VDOPageCache *cache) __attribute__((warn_unused_result)); /** * Advance the dirty period for a page cache. * * @param cache The cache to advance * @param period The new dirty period **/ void advanceVDOPageCachePeriod(VDOPageCache *cache, SequenceNumber period); /** * Write one or more batches of dirty pages. * * All writable pages in the ancient era and some number in the old era * are scheduled for writing. * * @param cache the VDO page cache * @param batches how many batches to write now * @param total how many batches (including those being written now) remain * in this era **/ void writeVDOPageCachePages(VDOPageCache *cache, size_t batches, size_t total); /** * Rotate the dirty page eras. * * Move all pages in the old era to the ancient era and then move * the current era bin into the old era. * * @param cache the VDO page cache **/ void rotateVDOPageCacheEras(VDOPageCache *cache); // ASYNC /** * A completion awaiting a specific page. Also a live reference into the * page once completed, until freed. **/ typedef struct { /** The generic completion */ VDOCompletion completion; /** The cache involved */ VDOPageCache *cache; /** The waiter for the pending list */ Waiter waiter; /** The absolute physical block number of the page on disk */ PhysicalBlockNumber pbn; /** Whether the page may be modified */ bool writable; /** Whether the page is available */ bool ready; /** The info structure for the page, only valid when ready */ PageInfo *info; } VDOPageCompletion; /** * Initialize a VDO Page Completion, requesting a particular page from the * cache. * * @param pageCompletion The VDOPageCompletion to initialize * @param cache The VDO page cache * @param pbn The absolute physical block of the desired page * @param writable Whether the page can be modified * @param parent The parent object * @param callback The completion callback * @param errorHandler The handler for page errors * * @note Once a completion has occurred for the getVDOPageAsync operation, * the underlying page shall be busy (stuck in memory) until the * VDOCompletion returned by this operation has been released. **/ void initVDOPageCompletion(VDOPageCompletion *pageCompletion, VDOPageCache *cache, PhysicalBlockNumber pbn, bool writable, void *parent, VDOAction *callback, VDOAction *errorHandler); /** * Release a VDO Page Completion. * * The page referenced by this completion (if any) will no longer be * held busy by this completion. If a page becomes discardable and * there are completions awaiting free pages then a new round of * page discarding is started. * * @param completion The completion to release **/ void releaseVDOPageCompletion(VDOCompletion *completion); /** * Asynchronous operation to get a VDO page. * * May cause another page to be discarded (potentially writing a dirty page) * and the one nominated by the completion to be loaded from disk. * * When the page becomes available the callback registered in the completion * provided is triggered. Once triggered the page is marked busy until * the completion is destroyed. * * @param completion the completion initialized my initVDOPageCompletion(). **/ void getVDOPageAsync(VDOCompletion *completion); /** * Mark a VDO page referenced by a completed VDOPageCompletion as dirty. * * @param completion a VDO Page Completion whose callback has been called * @param oldDirtyPeriod the period in which the page was already dirty (0 if * it wasn't) * @param newDirtyPeriod the period in which the page is now dirty **/ void markCompletedVDOPageDirty(VDOCompletion *completion, SequenceNumber oldDirtyPeriod, SequenceNumber newDirtyPeriod); /** * Request that a VDO page be written out as soon as it is not busy. * * @param completion the VDOPageCompletion containing the page **/ void requestVDOPageWrite(VDOCompletion *completion); /** * Access the raw memory for a read-only page of a completed VDOPageCompletion. * * @param completion a vdo page completion whose callback has been called * * @return a pointer to the raw memory at the beginning of the page, or * NULL if the page is not available. **/ const void *dereferenceReadableVDOPage(VDOCompletion *completion); /** * Access the raw memory for a writable page of a completed VDOPageCompletion. * * @param completion a vdo page completion whose callback has been called * * @return a pointer to the raw memory at the beginning of the page, or * NULL if the page is not available, or if the page is read-only **/ void *dereferenceWritableVDOPage(VDOCompletion *completion); /** * Get the per-page client context for the page in a page completion whose * callback has been invoked. Should only be called after dereferencing the * page completion to validate the page. * * @param completion a vdo page completion whose callback has been invoked * * @return a pointer to the per-page client context, or NULL if * the page is not available **/ void *getVDOPageCompletionContext(VDOCompletion *completion); /** * Drain I/O for a page cache. * * @param cache The cache to drain **/ void drainVDOPageCache(VDOPageCache *cache); /** * Invalidate all entries in the VDO page cache. There must not be any * dirty pages in the cache. * * @param cache the cache to invalidate * * @return a success or error code **/ int invalidateVDOPageCache(VDOPageCache *cache) __attribute__((warn_unused_result)); // STATISTICS & TESTING /** * Get current cache statistics. * * @param cache the page cache * * @return the statistics **/ AtomicPageCacheStatistics *getVDOPageCacheStatistics(VDOPageCache *cache) __attribute__((warn_unused_result)); #endif // VDO_PAGE_CACHE_H