diff --git a/lladd/pageHandle.h b/lladd/pageHandle.h new file mode 100644 index 0000000..e5b5bdf --- /dev/null +++ b/lladd/pageHandle.h @@ -0,0 +1,55 @@ +#include +#include +/** + * Write page to disk, including correct LSN. Doing so may require a + * call to logSync(). There is not much that can be done to avoid + * this call right now. In the future, it might make sense to check + * to see if some other page can be kicked, in order to avoid the log + * flush. + * + * This funciton is automatically called immediately before a page is + * evicted from cache. Operation implementors, and normal users + * should never have to call this routine. + * + * @see bufferManager.c for the implementation of pageWrite + * + * @param dat The page to be flushed to disk. No concurrent calls + * may have the same value of dat. + */ +extern void (*pageWrite)(Page * dat); + +extern int pageFile_isDurable; + +/** + Read a page from disk. This bypassess the cache, and should only be + called by bufferManager and blobManager. To retrieve a page under + normal circumstances, use loadPage() instead. + + Operation implementors and normal users should never need to call + this routine. + + @param ret A page struct, with id set correctly. The rest of this + struct will be overwritten by pageMap. This method assumes that no + concurrent calls will be passed the same value of ret. + + @see bufferManager.c for the implementation of pageRead. + + @todo pageRead and pageWrite should be static, but pageCache needs + to call them. +*/ +extern void (*pageRead)(Page * ret); +/** + Force the page file to disk. Pages that have had pageWrite() + called on them are guaranteed to be on disk after this returns. + + (Note that bufferManager implementations typically call pageWrite() + automatically, so in general, other pages could be written back + as well...) +*/ +extern void (*forcePageFile)(); +/** + Force the page file to disk, then close it. +*/ +extern void (*closePageFile)(); + +void pageHandleOpen(stasis_handle_t * handle); diff --git a/src/lladd/pageHandle.c b/src/lladd/pageHandle.c new file mode 100644 index 0000000..db2f8bb --- /dev/null +++ b/src/lladd/pageHandle.c @@ -0,0 +1,71 @@ +#include +#include +#include +#include +#include +#include +#include +#include +void (*pageWrite)(Page * dat); +void (*pageRead)(Page * ret); +void (*forcePageFile)(); +void (*closePageFile)(); + +int printedForceWarning = 0; + +static stasis_handle_t * h; +/** + @todo Make sure this doesn't need to be atomic. (It isn't!) Can + we get in trouble by setting the page clean after it's written + out, or forcing the log too early? +*/ +static void phWrite(Page * ret) { + assert(ret->LSN == pageReadLSN(ret)); + if(!ret->dirty) { return; } + LogForce(ret->LSN); + int err = h->write(h, PAGE_SIZE * ret->id, ret->memAddr, PAGE_SIZE); + if(err) { + printf("Couldn't write to page file: %s\n", strerror(err)); + fflush(stdout); + abort(); + } + dirtyPages_remove(ret); +} + +static void phRead(Page * ret) { + int err = h->read(h, PAGE_SIZE * ret->id, ret->memAddr, PAGE_SIZE); + if(err) { + if(err == EDOM) { + // tried to read off end of file... + memset(ret->memAddr, 0, PAGE_SIZE); + } else { + printf("Couldn't read from page file: %s\n", strerror(err)); + fflush(stdout); + abort(); + } + } + ret->dirty = 0; + ret->LSN = *lsn_ptr(ret); +} +static void phForce() { + if(!printedForceWarning) { + printf("Warning! pageHandle can't force the page file yet!\n"); + fflush(stdout); + } +} +static void phClose() { + int err = h->close(h); + if(err) { + printf("Couldn't close page file: %s\n", strerror(err)); + fflush(stdout); + abort(); + } +} + +void pageHandleOpen(stasis_handle_t * handle) { + pageWrite = phWrite; + pageRead = phRead; + forcePageFile = phForce; + closePageFile = phClose; + h = handle; +}