#include #include #include #include #include #include "../blobManager.h" #include "../page.h" #include "../page/slotted.h" #include /** @file Implementation of Talloc() as an operation This is a bit strange compared to other operations, as it happens in two phases. The buffer manager reserves space for a record before the log entry is allocated. Then, the recordid of this space is written to the log. Finally, alloc tells bufferManager that it will use the space. @todo Currently, if the system crashes during an alloc, (before the log is flushed, but after bufferManager returns a rid), then the space alloced during the crash is leaked. This doesn't seem to be too big of a deal, but it should be fixed someday. A more serious problem results from crashes during blob allocation. @ingroup OPERATIONS $Id$ */ static int operate(int xid, Page * p, lsn_t lsn, recordid rid, const void * dat) { /* * @ todo Currently, Talloc() needs to clean up the page type (for recovery). Should this be elsewhere? */ /* if(*page_type_ptr(p) == UNINITIALIZED_PAGE) { *page_type_ptr(p) = SLOTTED_PAGE; } assert(*page_type_ptr(p) == SLOTTED_PAGE); */ if(rid.size >= BLOB_THRESHOLD_SIZE && rid.size != BLOB_SLOT) { allocBlob(xid, p, lsn, rid); } else { slottedPostRalloc(xid, p, lsn, rid); } return 0; } /** @todo Currently, we leak empty pages on dealloc. */ static int deoperate(int xid, Page * p, lsn_t lsn, recordid rid, const void * dat) { assert(rid.page == p->id); slottedDeRalloc(xid, p, lsn, rid); return 0; } static int reoperate(int xid, Page *p, lsn_t lsn, recordid rid, const void * dat) { if(rid.size >= BLOB_THRESHOLD_SIZE && rid.size != BLOB_SLOT) { // rid.size = BLOB_REC_SIZE; /* Don't reuse blob space yet... */ rid.size = sizeof(blob_record_t); } slottedPostRalloc(xid, p, lsn, rid); /** @todo dat should be the pointer to the space in the blob store. */ writeRecord(xid, p, lsn, rid, dat); return 0; } static pthread_mutex_t talloc_mutex; Operation getAlloc() { pthread_mutex_init(&talloc_mutex, NULL); Operation o = { OPERATION_ALLOC, /* ID */ 0, OPERATION_DEALLOC, /* OPERATION_NOOP, */ &operate }; return o; } Operation getDealloc() { Operation o = { OPERATION_DEALLOC, SIZEOF_RECORD, OPERATION_REALLOC, /* OPERATION_NOOP, */ &deoperate }; return o; } /*This is only used to undo deallocs... */ Operation getRealloc() { Operation o = { OPERATION_REALLOC, 0, OPERATION_NOOP, &reoperate }; return o; } recordid Talloc(int xid, long size) { recordid rid; Page * p = NULL; if(size >= BLOB_THRESHOLD_SIZE && size != BLOB_SLOT) { /**@todo is it OK that Talloc doesn't pin the page when a blob is alloced?*/ rid = preAllocBlob(xid, size); } else { pthread_mutex_lock(&talloc_mutex); rid = slottedPreRalloc(xid, size, &p); assert(p != NULL); } Tupdate(xid,rid, NULL, OPERATION_ALLOC); if(p != NULL) { /* release the page that preAllocBlob pinned for us. */ /* @todo alloc.c pins multiple pages -> Will deadlock with small buffer sizes.. */ releasePage(p); pthread_mutex_unlock(&talloc_mutex); } return rid; } recordid TallocFromPage(int xid, long page, long size) { recordid rid; Page * p = NULL; if(size >= BLOB_THRESHOLD_SIZE && size != BLOB_SLOT) { rid = preAllocBlobFromPage(xid, page, size); } else { pthread_mutex_lock(&talloc_mutex); rid = slottedPreRallocFromPage(xid, page, size, &p); if(p == NULL) { assert(rid.size == -1); pthread_mutex_unlock(&talloc_mutex); return rid; } } Tupdate(xid,rid, NULL, OPERATION_ALLOC); if(p != NULL) { /* release the page that preRallocFromPage pinned for us. */ /* @todo alloc.c pins multiple pages -> Will deadlock with small buffer sizes.. */ releasePage(p); pthread_mutex_unlock(&talloc_mutex); } return rid; } void Tdealloc(int xid, recordid rid) { void * preimage = malloc(rid.size); Page * p = loadPage(xid, rid.page); readRecord(xid, p, rid, preimage); /** @todo race in Tdealloc; do we care, or is this something that the log manager should cope with? */ Tupdate(xid, rid, preimage, OPERATION_DEALLOC); releasePage(p); free(preimage); } int TrecordType(int xid, recordid rid) { Page * p = loadPage(xid, rid.page); int ret = getRecordType(xid, p, rid); releasePage(p); return ret; } int TrecordSize(int xid, recordid rid) { int ret; Page * p = loadPage(xid, rid.page); ret = getRecordSize(xid, p, rid); releasePage(p); return ret; } int TrecordsInPage(int xid, int pageid) { Page * p = loadPage(xid, pageid); readlock(p->rwlatch, 187); int ret = *numslots_ptr(p); unlock(p->rwlatch); releasePage(p); return ret; }