diff --git a/lladd.pws b/lladd.pws index acb7acb..475703a 100644 --- a/lladd.pws +++ b/lladd.pws @@ -11,24 +11,50 @@ filter.file.ignore.hidden=0 filter.dir.ignore.hidden=0 [filenumbers] -0=22 -1=1 -2=12 -3=2 -4=50 -5=3 -6=25 -7=24 -8=30 +0=170 +1=70 +2=21 +3=50 +4=1 +5=1 +6=89 +7=22 +8=1 9=1 -10=67 -11=1 -12=17 -13=1 -14=104 -15=387 -16=58 -17=8 +10=153 +11=102 +12=4 +13=6 +14=1 +15=69 +16=148 +17=1 +18=1 +19=1 +20=13 +21=43 +22=87 +23=2 +24=1 +25=106 +26=106 +27=124 +28=151 +29=158 +30=324 +31=145 +32=46 +33=5 +34=38 +35=49 +36=11 +37=47 +38=76 +39=29 +40=1 +41=324 +42=66 +43=167 [filemarkers] 0= @@ -49,16 +75,78 @@ filter.dir.ignore.hidden=0 15= 16= 17= +18= +19= +20= +21= +22= +23= +24= +25= +26= +27= +28= +29= +30= +31= +32= +33= +34= +35= +36= +37= +38= +39= +40= +41= +42= +43= [filelist] -0=/home/sears/lladd/libdfa/messages.h -1=/home/sears/lladd/test/dfa/Makefile.am -2=/home/sears/lladd/test/lladd/Makefile.am -3=/home/sears/lladd/test/lladd/check_blobRecovery.c -4=/home/sears/lladd/test/dfa/check_networksetup.c -5=/home/sears/lladd/libdfa/networksetup.sample -6=/home/sears/lladd/src/libdfa/networksetup.c -7=/home/sears/lladd/libdfa/networksetup.h +0=/home/sears/lladd/src/lladd/page/slotted.h +1=/home/sears/lladd/lladd/operations/pageOrientedListNTA.h +2=/home/sears/lladd/src/lladd/operations/pageOrientedListNTA.c +3=/home/sears/lladd/lladd/operations/linkedListNTA.h +4=/home/sears/lladd/src/lladd/operations/linkedListNTA.c +5=/home/sears/lladd/lladd/operations/linearHashNTA.h +6=/home/sears/lladd/lladd/operations/prepare.h +7=/home/sears/lladd/lladd/operations/alloc.h +8=/home/sears/lladd/benchmarks/berkeleyDB/Makefile.am +9=/home/sears/lladd/benchmarks/berkeleyDB/bdbRaw.c +10=/home/sears/lladd/lladd/transactional.h +11=/home/sears/lladd/doc/index.html +12=/home/sears/lladd/test/cht/run +13=/home/sears/lladd/test/cht/Makefile.am +14=/home/sears/lladd/src/apps/cht/Makefile.am +15=/home/sears/lladd/configure.in +16=/home/sears/lladd/src/lladd/logger/logWriter.c +17=/home/sears/lladd/src/lladd/operations/alloc.c +18=/home/sears/lladd/lladd/constants.h +19=/home/sears/lladd/src/lladd/operations.c +20=/home/sears/lladd/test/cht/subordinate.c +21=/home/sears/lladd/src/libdfa/callbacks.c +22=/home/sears/lladd/src/2pc/2pc.h +23=/home/sears/lladd/test/2pc/Makefile.am +24=/home/sears/lladd/test/cht/cht_server.c +25=/home/sears/lladd/test/cht/simple.c +26=/home/sears/lladd/test/2pc/always_commit.c +27=/home/sears/lladd/test/dfa/star.c +28=/home/sears/lladd/src/apps/cht/cht.h +29=/home/sears/lladd/libdfa/libdfa.h +30=/home/sears/lladd/src/libdfa/libdfa.c +31=/home/sears/lladd/src/apps/cht/cht_client.c +32=/home/sears/lladd/src/lladd/operations/linearHashNTA.c +33=/home/sears/lladd/test/cht/client.conf +34=/home/sears/lladd/libdfa/networksetup.h +35=/home/sears/lladd/src/apps/cht/cht.c +36=/home/sears/lladd/test/cht/cluster.conf +37=/home/sears/lladd/test/cht/client.c +38=/home/sears/lladd/src/libdfa/networksetup.c +39=/home/sears/lladd/src/apps/cht/cht_server.c +40=/home/sears/lladd/src/apps/cht/cht_message.c +41=/home/sears/lladd/src/libdfa/messages.c +42=/home/sears/lladd/libdfa/messages.h +43=/home/sears/lladd/src/2pc/2pc.c [Project Tree] 0=0 @@ -73,11 +161,12 @@ filter.dir.ignore.hidden=0 [File Tree] 0=0 -1=0:5 -2=0:6 -3=0:9 -4=0:10 -5=0:11 +1=0:6 +2=0:6:2 +3=0:10 +4=0:10:4 +5=0:10:4:4 +6=0:12 [executer args] 0=check_linearHash diff --git a/lladd/operations.h b/lladd/operations.h index 41acb1d..93b433d 100644 --- a/lladd/operations.h +++ b/lladd/operations.h @@ -164,6 +164,7 @@ typedef struct { #include "operations/nestedTopActions.h" #include "operations/linkedListNTA.h" #include "operations/linearHashNTA.h" +#include "operations/pageOrientedListNTA.h" extern Operation operationsTable[]; /* [MAX_OPERATIONS]; memset somewhere */ diff --git a/lladd/operations/alloc.h b/lladd/operations/alloc.h index 3f1c13f..00a5f01 100644 --- a/lladd/operations/alloc.h +++ b/lladd/operations/alloc.h @@ -30,6 +30,8 @@ Operation getRealloc(); */ recordid Talloc(int xid, long size); +recordid TallocFromPage(int xid, long page, long size); + /** Free a record. @todo Currently, we just leak store space on dealloc. @@ -37,12 +39,33 @@ recordid Talloc(int xid, long size); void Tdealloc(int xid, recordid rid); /** - Return the type of a record, as returned by getRecordType. + Obtain the type of a record, as returned by getRecordType. + + @param xid the transaction id. + + @param rid the record of interest. The size field will be ignored, + allowing this function to be used to probe for records in pages. - @todo document TrecordType - @see getRecordType + @return UNINITIALIZED_RECORD, BLOB_RECORD, SLOTTED_RECORD, or FIXED_RECORD. + + @see getRecordType */ int TrecordType(int xid, recordid rid); +/** + Obtain the length of the data stored in a record. + + @param xid the transaction id. + + @param rid the record of interest. The size field will be ignored, + allowing this function to be used to probe for records in pages. + + @return -1 if the record does not exist, the size of the record otherwise. +*/ +int TrecordSize(int xid, recordid rid); + +/** Return the number of records stored in page pageid */ +int TrecordsInPage(int xid, int pageid); + #endif diff --git a/lladd/operations/pageOrientedListNTA.h b/lladd/operations/pageOrientedListNTA.h new file mode 100644 index 0000000..acb29bd --- /dev/null +++ b/lladd/operations/pageOrientedListNTA.h @@ -0,0 +1,89 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ + +/** + @file + + A linked list implementation designed to handle variable length entries, and + minimize the number of pages spanned by each list. + + The data is stored using the slotted page implementation. + + slot 0 is a long that points to the next page in the list. + + The rest of the slots store data. + + $Id $ +*/ + +#ifndef __pageOrientedListNTA_H +#define __pageOrientedListNTA_H + + +typedef struct { + long page; + /* The slot of the next record to be returned. */ + int slot; +} lladd_pagedList_iterator; + +//recordid dereferencePagedListRID(int xid, recordid rid); +/** @return 1 if the key was already in the list. */ +int TpagedListInsert(int xid, recordid list, const byte * key, int keySize, const byte * value, int valueSize); +int TpagedListFind(int xid, recordid list, const byte * key, int keySize, byte ** value); +int TpagedListRemove(int xid, recordid list, const byte * key, int keySize); +int TpagedListMove(int xid, recordid start_list, recordid end_list, const byte *key, int keySize); +/** The linked list iterator can tolerate the concurrent removal of values that + it has already returned. In the presence of such removals, the iterator + will return the keys and values present in the list as it existed when next() + was first called. + + @return a new iterator initialized to the head of the list. */ +lladd_pagedList_iterator * TpagedListIterator(int xid, recordid list); +/** @return 1 if there was another entry to be iterated over. 0 otherwise. + If this function returns 1, the caller must free() the malloced memory + returned via the key and value arguments.*/ +int TpagedListNext(int xid, lladd_pagedList_iterator * it, byte ** key, int * keySize, byte ** value, int * valueSize); +recordid TpagedListAlloc(int xid); +void TpagedListDelete(int xid, recordid list); +Operation getPagedListInsert(); +Operation getPagedListRemove(); +#endif diff --git a/src/apps/cht/cht.c b/src/apps/cht/cht.c index 402025c..77786f1 100644 --- a/src/apps/cht/cht.c +++ b/src/apps/cht/cht.c @@ -46,7 +46,7 @@ terms specified in this license. #include #include "../../2pc/2pc.h" #include "../../libdfa/callbacks.h" -#include +//#include #include "cht_message.h" diff --git a/src/libdfa/messages.c b/src/libdfa/messages.c index 1922d95..8cf1c55 100644 --- a/src/libdfa/messages.c +++ b/src/libdfa/messages.c @@ -40,6 +40,9 @@ permission to use and distribute the software in accordance with the terms specified in this license. ---*/ /*#include */ + +#define _GNU_SOURCE + #include #include #include diff --git a/src/lladd/Makefile.am b/src/lladd/Makefile.am index 11def94..484029f 100644 --- a/src/lladd/Makefile.am +++ b/src/lladd/Makefile.am @@ -10,6 +10,8 @@ liblladd_a_SOURCES=crc32.c common.c stats.c io.c bufferManager.c linkedlist.c op operations/increment.c operations/prepare.c operations/set.c \ operations/alloc.c operations/noop.c operations/instantSet.c \ page/slotted.c operations/lladdhash.c page/header.c page/fixed.c \ - operations/arrayList.c hash.c operations/linearHash.c operations/naiveLinearHash.c \ - operations/nestedTopActions.c operations/linearHashNTA.c operations/linkedListNTA.c + operations/arrayList.c hash.c operations/linearHash.c \ + operations/naiveLinearHash.c operations/nestedTopActions.c \ + operations/linearHashNTA.c operations/linkedListNTA.c \ + operations/pageOrientedListNTA.c AM_CFLAGS= -g -Wall -pedantic -std=gnu99 diff --git a/src/lladd/blobManager.c b/src/lladd/blobManager.c index 0e8f022..0e35381 100644 --- a/src/lladd/blobManager.c +++ b/src/lladd/blobManager.c @@ -213,6 +213,24 @@ recordid preAllocBlob(int xid, long blobSize) { } +recordid preAllocBlobFromPage(int xid, long page, long blobSize) { + + /* Allocate space for the blob entry. */ + + DEBUG("Allocing blob (size %ld)\n", blobSize); + + assert(blobSize > 0); /* Don't support zero length blobs right now... */ + + /* First in buffer manager. */ + + recordid rid = TallocFromPage(xid, page, sizeof(blob_record_t)); + + rid.size = blobSize; + + return rid; + +} + void allocBlob(int xid, Page * p, lsn_t lsn, recordid rid) { long fileSize; diff --git a/src/lladd/blobManager.h b/src/lladd/blobManager.h index 0bb7822..459fcd4 100644 --- a/src/lladd/blobManager.h +++ b/src/lladd/blobManager.h @@ -78,6 +78,7 @@ typedef struct { recordid preAllocBlob(int xid, long blobsize); +recordid preAllocBlobFromPage(int xid, long page, long blobsize); /** Allocate a blob of size blobSize. diff --git a/src/lladd/operations/alloc.c b/src/lladd/operations/alloc.c index 490c2f8..ddb93c0 100644 --- a/src/lladd/operations/alloc.c +++ b/src/lladd/operations/alloc.c @@ -109,6 +109,7 @@ recordid Talloc(int xid, long size) { recordid rid; Page * p = NULL; if(size >= BLOB_THRESHOLD_SIZE) { + /**@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); @@ -133,6 +134,29 @@ recordid Talloc(int xid, long size) { } +recordid TallocFromPage(int xid, long page, long size) { + recordid rid; + + Page * p = NULL; + if(size >= BLOB_THRESHOLD_SIZE) { + rid = preAllocBlobFromPage(xid, page, size); + } else { + pthread_mutex_lock(&talloc_mutex); + rid = slottedPreRallocFromPage(xid, page, size, &p); + assert(p != NULL); + } + 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(rid.page); @@ -149,3 +173,20 @@ int TrecordType(int xid, recordid rid) { releasePage(p); return ret; } + +int TrecordSize(int xid, recordid rid) { + int ret; + Page * p = loadPage(rid.page); + ret = getRecordSize(xid, p, rid); + releasePage(p); + return ret; +} + +int TrecordsInPage(int xid, int pageid) { + Page * p = loadPage(pageid); + readlock(p->rwlatch, 187); + int ret = *numslots_ptr(p); + unlock(p->rwlatch); + releasePage(p); + return ret; +} diff --git a/src/lladd/operations/pageOrientedListNTA.c b/src/lladd/operations/pageOrientedListNTA.c new file mode 100644 index 0000000..c1050b0 --- /dev/null +++ b/src/lladd/operations/pageOrientedListNTA.c @@ -0,0 +1,247 @@ +#include +#include "../blobManager.h" +#include "../page.h" +#include "../page/slotted.h" +#include +#include +/** + Low level function that looks at the page structure, and finds the 'real' recordid + of a page oriented list rid */ +/*recordid dereferencePagedListRID(int xid, recordid rid) { + Page * p = loadPage(rid.page); + while((*numslots_ptr(p)-POLL_NUM_RESERVED) <= rid.slot) { + int oldSlot = rid.slot; + oldSlot -= (*numslots_ptr(p) - POLL_NUM_RESERVED); + rid.slot = POLL_NEXT; + readRecord(xid, p , rid, &rid); + rid.slot = oldSlot; + releasePage(p); + p = loadPage(rid.page); + } + releasePage(p); + rid.slot+=POLL_NUM_RESERVED; + return rid; +}*/ + +recordid TpagedListAlloc(int xid) { + long page = TpageAlloc(xid); + recordid list = TallocFromPage(xid, page, sizeof(long)); + long zero = 0; + Tset(xid, list, &zero); + assert(list.slot == 0); + assert(list.size == sizeof(long)); + return list; +} + +int TpagedListInsert(int xid, recordid list, const byte * key, int keySize, const byte * value, int valueSize) { + int ret = 0; + // if find in list, return 1 + byte * val; + if(keySize == TpagedListFind(xid, list, key, keySize, &val)) { + + free(val); + ret = 1; + int removed = TpagedListRemove(xid, list, key, keySize); + assert(removed); + // delete from list + } + Page * p = loadPage(list.page); + int recordSize = (sizeof(short)+keySize+valueSize); + int isBlob = recordSize >= BLOB_THRESHOLD_SIZE; + int realSize = recordSize; + if(isBlob) { + recordSize = sizeof(blob_record_t); + } + while(slottedFreespace(p) < recordSize) { + // load next page, update some rid somewhere + list.slot = 0; + list.size = sizeof(long); + long nextPage; + readRecord(xid, p, list, &nextPage); + // printf("+ page = %d nextpage=%ld freespace: %d recordsize: %d\n", list.page, nextPage, slottedFreespace(p), recordSize); fflush(stdout); + if(nextPage == 0) { + releasePage(p); + nextPage = TpageAlloc(xid); + Tset(xid, list, &nextPage); + p = loadPage(nextPage); + // slottedPageInitialize(p); + // ** @todo shouldn't a log entry be generated here?? */ + list.page = nextPage; + assert(slottedFreespace(p) >= recordSize); + long zero = 0; + TallocFromPage(xid, list.page, sizeof(long)); + Tset(xid, list, &zero); + } else { + releasePage(p); + list.page = nextPage; + p = loadPage(nextPage); + } + } + + if(isBlob) { + recordSize = realSize; + } + + releasePage(p); + + recordid rid = TallocFromPage(xid, list.page, recordSize); // Allocates a record at a location given by the caller + short* record = malloc(recordSize); + *record = keySize; + memcpy((record+1), key, keySize); + memcpy(((char*)(record+1))+keySize, value, valueSize); + Tset(xid, rid, record); + + return ret; +} +int TpagedListFind(int xid, recordid list, const byte * key, int keySize, byte ** value) { + + long nextPage = 1; + + while (nextPage) { + int i; + int pageCount = TrecordsInPage(xid, list.page); + + // printf("%ld\n", nextPage); + fflush(stdout); + + for(i = 1; i < pageCount; i++) { + recordid entry = list; + entry.slot = i; + int length = TrecordSize(xid, entry); + if(length != -1) { // then entry is defined. + short * dat = malloc(length); + entry.size = length; + Tread(xid, entry, dat); + + if(*dat == keySize && !memcmp(dat+1, key, keySize)) { + int valueSize = length-keySize-sizeof(short); + *value = malloc(valueSize); + + memcpy(*value, ((byte*)(dat+1))+keySize, valueSize); + + free(dat); + return valueSize; + } + free(dat); + } + } + + // recordid rid = list; + + list.slot = 0; + list.size = sizeof(long); + + Tread(xid, list, &nextPage); + + list.page = nextPage; + } + return 0; +} +int TpagedListRemove(int xid, recordid list, const byte * key, int keySize) { + long nextPage = 1; + + while (nextPage) { + int i; + int pageCount = TrecordsInPage(xid, list.page); + + // printf("%ld\n", nextPage); + fflush(stdout); + + for(i = 1; i < pageCount; i++) { + recordid entry = list; + entry.slot = i; + int length = TrecordSize(xid, entry); + if(length != -1) { // then entry is defined. + short * dat = malloc(length); + entry.size = length; + Tread(xid, entry, dat); + + if(*dat == keySize && !memcmp(dat+1, key, keySize)) { + Tdealloc(xid, entry); + + free(dat); + return 1; + } + free(dat); + } + } + + list.slot = 0; + list.size = sizeof(long); + + Tread(xid, list, &nextPage); + + list.page = nextPage; + } + return 0; + +} +int TpagedListMove(int xid, recordid start_list, recordid end_list, const byte *key, int keySize) { + byte * value; + int valueSize = TpagedListFind(xid, start_list, key, keySize, &value); + if(valueSize) { + int ret = TpagedListRemove(xid, start_list, key, keySize); + assert(ret); + ret = TpagedListInsert(xid, end_list, key, keySize, value, valueSize); + assert(!ret); + free(value); + return 1; + } else { + return 0; + } +} + +lladd_pagedList_iterator * TpagedListIterator(int xid, recordid list) { + lladd_pagedList_iterator * ret = malloc(sizeof(lladd_pagedList_iterator)); + + ret->page = list.page; + ret->slot = 1; + + return ret; +} + +int TpagedListNext(int xid, lladd_pagedList_iterator * it, + byte ** key, int * keySize, + byte ** value, int * valueSize) { + // printf("next: page %d slot %d\n", it->page, it->slot); + recordid rid; + while(it->page) { + while(it->slot < TrecordsInPage(xid, it->page)) { + rid.page = it->page; + rid.slot = it->slot; + rid.size=TrecordSize(xid, rid); + if(rid.size != -1) { + // found entry! + + byte * dat = malloc(rid.size); + Tread(xid, rid, dat); + + // populate / alloc pointers passed in by caller. + + *keySize = *(short*)dat; + *valueSize = rid.size - *keySize - sizeof(short); + + *key = malloc(*keySize); + *value = malloc(*valueSize); + + memcpy(*key, ((short*)dat)+1, *keySize); + memcpy(*value, ((byte*)(((short*)dat)+1)) + *keySize, *valueSize); + + free(dat); + it->slot++; + return 1; + } + it->slot++; + } + rid.page = it->page; + rid.slot = 0; + rid.size = sizeof(long); + Tread(xid, rid, &(it->page)); + it->slot = 1; + + } + free(it); + + return 0; + +} diff --git a/src/lladd/page.c b/src/lladd/page.c index 3ded7a5..3bc8ee4 100644 --- a/src/lladd/page.c +++ b/src/lladd/page.c @@ -315,31 +315,27 @@ void readRecordUnlocked(int xid, Page * p, recordid rid, void *buf) { */ int getRecordTypeUnlocked(int xid, Page * p, recordid rid) { - assert(rid.page == p->id); - - int page_type = *page_type_ptr(p); - - if(page_type == UNINITIALIZED_PAGE) { - return UNINITIALIZED_RECORD; - - } else if(rid.size > BLOB_THRESHOLD_SIZE) { -// printf("%d , %d\n", *numslots_ptr(p), *slot_length_ptr(p, rid.slot)); - return(*numslots_ptr(p) > rid.slot && - *slot_length_ptr(p, rid.slot) == BLOB_REC_SIZE) ? - BLOB_RECORD : UNINITIALIZED_RECORD; - - } else if(page_type == SLOTTED_PAGE) { - return (*numslots_ptr(p) > rid.slot && - *slot_length_ptr(p, rid.slot) != INVALID_SLOT) ? - SLOTTED_RECORD : UNINITIALIZED_RECORD; - - } else if(page_type == FIXED_PAGE || page_type == ARRAY_LIST_PAGE) { - return (fixedPageCount(p) > rid.slot) ? - FIXED_RECORD : UNINITIALIZED_RECORD; - } else { - abort(); - return UNINITIALIZED_RECORD; - } + assert(rid.page == p->id); + + int page_type = *page_type_ptr(p); + if(page_type == UNINITIALIZED_PAGE) { + return UNINITIALIZED_RECORD; + + } else if(page_type == SLOTTED_PAGE) { + if(*numslots_ptr(p) <= rid.slot || *slot_length_ptr(p, rid.slot) == INVALID_SLOT) { + return UNINITIALIZED_PAGE; + } else if(*slot_length_ptr(p, rid.slot) == BLOB_REC_SIZE) { + return BLOB_RECORD; + } else { + return SLOTTED_RECORD; + } + } else if(page_type == FIXED_PAGE || page_type == ARRAY_LIST_PAGE) { + return (fixedPageCount(p) > rid.slot) ? + FIXED_RECORD : UNINITIALIZED_RECORD; + } else { + abort(); + return UNINITIALIZED_RECORD; + } } int getRecordType(int xid, Page * p, recordid rid) { @@ -348,6 +344,20 @@ int getRecordType(int xid, Page * p, recordid rid) { unlock(p->rwlatch); return ret; } +/** @todo implemenet getRecordLength for blobs and fixed length pages. */ +int getRecordSize(int xid, Page * p, recordid rid) { + readlock(p->rwlatch, 353); + int ret = getRecordTypeUnlocked(xid, p, rid); + if(ret == UNINITIALIZED_RECORD) { + ret = -1; + } else if(ret == SLOTTED_RECORD) { + ret = *slot_length_ptr(p, rid.slot); + } else { + abort(); // unimplemented for fixed length pages and blobs. + } + unlock(p->rwlatch); + return ret; +} void writeRecordUnlocked(int xid, Page * p, lsn_t lsn, recordid rid, const void *dat) { diff --git a/src/lladd/page.h b/src/lladd/page.h index f6e356a..7e48052 100644 --- a/src/lladd/page.h +++ b/src/lladd/page.h @@ -298,12 +298,26 @@ void pageRealloc(Page * p, int id); /*int pageAlloc() ;*/ /** obtains the type of the record pointed to by rid. + + @return UNINITIALIZED_RECORD, BLOB_RECORD, SLOTTED_RECORD, or FIXED_RECORD. */ + + int getRecordType(int xid, Page * p, recordid rid); + +int getRecordSize(int xid, Page * p, recordid rid); /** same as getRecordType(), but does not obtain a lock. */ int getRecordTypeUnlocked(int xid, Page * p, recordid rid); +/** + return the length of the record rid. (the rid parameter's size field will be ignored) + + @todo implement getRecordLength for blobs and fixed length pages. + + @return -1 if the field does not exist, the size of the field otherwise. + */ +int getRecordLength(int xid, Page * p, recordid rid); END_C_DECLS diff --git a/src/lladd/page/slotted.c b/src/lladd/page/slotted.c index e81af54..da2f281 100644 --- a/src/lladd/page/slotted.c +++ b/src/lladd/page/slotted.c @@ -160,17 +160,12 @@ int slottedFreespace(Page * page) { recordid slottedPreRalloc(int xid, long size, Page ** pp) { recordid ret; - /* Page * p; */ - - /* DEBUG("Rallocing record of size %ld\n", (long int)size); */ - assert(size < BLOB_THRESHOLD_SIZE); - /* pthread_mutex_lock(&lastFreepage_mutex); */ /** @todo is ((unsigned int) foo) == -1 portable? Gotta love C.*/ - /*printf("lastFreepage %d\n", lastFreepage); fflush(NULL); */ + if(lastFreepage == -1) { - lastFreepage = TpageAlloc(xid/*, SLOTTED_PAGE*/); + lastFreepage = TpageAlloc(xid); *pp = loadPage(lastFreepage); assert(*page_type_ptr(*pp) == UNINITIALIZED_PAGE); slottedPageInitialize(*pp); @@ -180,23 +175,33 @@ recordid slottedPreRalloc(int xid, long size, Page ** pp) { if(slottedFreespace(*pp) < size ) { releasePage(*pp); - lastFreepage = TpageAlloc(xid/*, SLOTTED_PAGE*/); + lastFreepage = TpageAlloc(xid); *pp = loadPage(lastFreepage); slottedPageInitialize(*pp); } ret = slottedRawRalloc(*pp, size); - - /* releasePage(p); */ /* This gets called in Talloc() now. That prevents the page from being prematurely stolen. */ - - /* pthread_mutex_unlock(&lastFreepage_mutex); */ DEBUG("alloced rid = {%d, %d, %ld}\n", ret.page, ret.slot, ret.size); return ret; } - +recordid slottedPreRallocFromPage(int xid, long page, long size, Page **pp) { + recordid ret; + + *pp = loadPage(page); + + assert(slottedFreespace(*pp) >= size); + if(*page_type_ptr(*pp) == UNINITIALIZED_PAGE) { + slottedPageInitialize(*pp); + } + assert(*page_type_ptr(*pp) == SLOTTED_PAGE); + ret = slottedRawRalloc(*pp, size); + + return ret; + +} recordid slottedRawRalloc(Page * page, int size) { diff --git a/src/lladd/page/slotted.h b/src/lladd/page/slotted.h index 9f37f96..7d80467 100644 --- a/src/lladd/page/slotted.h +++ b/src/lladd/page/slotted.h @@ -92,6 +92,12 @@ void slottedPageInitialize(Page * p); * */ recordid slottedPreRalloc(int xid, long size, Page**p); +/** + Identical to slottedPreRalloc, but allows the user to specify which page the + record should be allocated in. + */ +recordid slottedPreRallocFromPage(int xid, long page, long size, Page**p); + /** * The second phase of slot allocation. Called after the log entry * has been produced, and during recovery. diff --git a/test/cht/simple.c b/test/cht/simple.c index 808eee9..a5bae7c 100644 --- a/test/cht/simple.c +++ b/test/cht/simple.c @@ -39,10 +39,10 @@ authors grant the U.S. Government and others acting in its behalf permission to use and distribute the software in accordance with the terms specified in this license. ---*/ +#include #include "../../src/apps/cht/cht.h" #include -#include /** Thanks, jbhtsimple.c!! */ diff --git a/test/lladd/Makefile.am b/test/lladd/Makefile.am index a4aa6d7..7fc1397 100644 --- a/test/lladd/Makefile.am +++ b/test/lladd/Makefile.am @@ -1,11 +1,11 @@ INCLUDES = @CHECK_CFLAGS@ if HAVE_CHECK ## Had to disable check_lht because lht needs to be rewritten. -TESTS = check_logEntry check_logWriter check_page check_operations check_transactional2 check_recovery check_blobRecovery check_bufferManager check_indirect check_lladdhash check_pageOperations check_linearHash check_logicalLinearHash check_header check_linkedListNTA check_linearHashNTA +TESTS = check_logEntry check_logWriter check_page check_operations check_transactional2 check_recovery check_blobRecovery check_bufferManager check_indirect check_lladdhash check_pageOperations check_linearHash check_logicalLinearHash check_header check_linkedListNTA check_linearHashNTA check_pageOrientedList else TESTS = endif noinst_PROGRAMS = $(TESTS) LDADD = @CHECK_LIBS@ $(top_builddir)/src/lladd/liblladd.a $(top_builddir)/src/pbl/libpbl.a $(top_builddir)/src/libdfa/librw.a # -lefence -CLEANFILES = check_lht.log check_logEntry.log storefile.txt logfile.txt blob0_file.txt blob1_file.txt check_blobRecovery.log check_logWriter.log check_operations.log check_recovery.log check_transactional2.log check_page.log check_bufferManager.log check_indirect.log check_bufferMananger.log check_lladdhash.log check_pageOperations.log check_linearhash.log check_linkedListNTA.log check_linearHashNTA.log +CLEANFILES = check_lht.log check_logEntry.log storefile.txt logfile.txt blob0_file.txt blob1_file.txt check_blobRecovery.log check_logWriter.log check_operations.log check_recovery.log check_transactional2.log check_page.log check_bufferManager.log check_indirect.log check_bufferMananger.log check_lladdhash.log check_pageOperations.log check_linearhash.log check_linkedListNTA.log check_linearHashNTA.log check_pageOrientedListNTA.log AM_CFLAGS= -g -Wall -pedantic -std=gnu99 diff --git a/test/lladd/check_linearHash.c b/test/lladd/check_linearHash.c index fef26fa..94695dc 100644 --- a/test/lladd/check_linearHash.c +++ b/test/lladd/check_linearHash.c @@ -208,7 +208,7 @@ START_TEST(transactionalLinearHashTest) int xid = Tbegin(); - recordid foo = Talloc(xid, 1); + Talloc(xid, 1); // discard alloced rid... // printf("%d %d %ld\n", foo.page, foo.slot, foo.size); diff --git a/test/lladd/check_page.c b/test/lladd/check_page.c index 92de97a..eabbb24 100644 --- a/test/lladd/check_page.c +++ b/test/lladd/check_page.c @@ -399,11 +399,9 @@ START_TEST(pageCheckSlotTypeTest) { assert(getRecordType(xid, p, bad) == UNINITIALIZED_RECORD); bad.size = 100000; assert(getRecordType(xid, p, bad) == UNINITIALIZED_RECORD); - /** @todo this test could be better... The behavior for getRecordType in this - case (valid slot, invalid size) is a bit ambiguous. Maybe an INVALID_RECORDID - would be an appropriate return value... */ + /** getRecordType now ignores the size field, so this (correctly) returns SLOTTED_RECORD */ bad.slot = slot.slot; - assert(getRecordType(xid, p, bad) == UNINITIALIZED_RECORD); + assert(getRecordType(xid, p, bad) == SLOTTED_RECORD); releasePage(p); @@ -447,11 +445,9 @@ START_TEST(pageTrecordTypeTest) { assert(TrecordType(xid, bad) == UNINITIALIZED_RECORD); bad.size = 100000; assert(TrecordType(xid, bad) == UNINITIALIZED_RECORD); - /** @todo this test could be better... The behavior for getRecordType in this - case (valid slot, invalid size) is a bit ambiguous. Maybe an INVALID_RECORDID - would be an appropriate return value... */ + bad.slot = slot.slot; - assert(TrecordType(xid, bad) == UNINITIALIZED_RECORD); + assert(TrecordType(xid, bad) == SLOTTED_RECORD); Tcommit(xid); diff --git a/test/lladd/check_pageOrientedList.c b/test/lladd/check_pageOrientedList.c new file mode 100644 index 0000000..cdba14a --- /dev/null +++ b/test/lladd/check_pageOrientedList.c @@ -0,0 +1,195 @@ +/*--- +This software is copyrighted by the Regents of the University of +California, and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, +provided that existing copyright notices are retained in all copies +and that this notice is included verbatim in any distributions. No +written agreement, license, or royalty fee is required for any of the +authorized uses. Modifications to this software may be copyrighted by +their authors and need not follow the licensing terms described here, +provided that the new terms are clearly indicated on the first page of +each file where they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND +THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" in +the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are +acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. +---*/ + +#include +#include + +#include + +#include +#include "../check_includes.h" + +#define LOG_NAME "check_pageOrientedListNTA.log" +/** @test */ +#define NUM_ENTRIES 2000 +START_TEST(pagedListCheck) { + Tinit(); + + int xid = Tbegin(); + + recordid list = TpagedListAlloc(xid); + + int a; + recordid b; + int i; + + printf("\n"); + for(i = 0; i < NUM_ENTRIES; i++) { + + if(!(i % (NUM_ENTRIES/10))) { + printf("."); fflush(stdout); + } + + a = i; + b.page = i+1; + b.slot = i+2; + b.size = i+3; + + int ret = TpagedListInsert(xid, list, (byte*)&a, sizeof(int), (byte*)&b, sizeof(recordid)); + + assert(!ret); + + recordid * bb; + ret = TpagedListFind(xid, list, (byte*)&a, sizeof(int), (byte**)&bb); + + assert(ret == sizeof(recordid)); + assert(!memcmp(bb, &b, sizeof(recordid))); + } + Tcommit(xid); + printf("\n"); + xid = Tbegin(); + for(i = 0; i < NUM_ENTRIES; i++ ) { + + if(!(i % (NUM_ENTRIES/10))) { + printf("."); fflush(stdout); + } + + a = i; + b.page = i+1; + b.slot = i+2; + b.size = i+3; + + recordid * bb; + int ret = TpagedListFind(xid, list, (byte*)&a, sizeof(int), (byte**)&bb); + + assert(ret == sizeof(recordid)); + assert(!memcmp(bb, &b, sizeof(recordid))); + + + if(!(i % 10)) { + + ret = TpagedListRemove(xid, list, (byte*)&a, sizeof(int)); + + assert(ret); + + free(bb); + bb = 0; + + ret = TpagedListFind(xid, list, (byte*)&a, sizeof(int), (byte**)&bb); + + assert(!ret); + assert(!bb); + } + } + Tabort(xid); + + xid = Tbegin(); + printf("\n"); + for(i = 0; i < NUM_ENTRIES; i++) { + + if(!(i % (NUM_ENTRIES/10))) { + printf("."); fflush(stdout); + } + + a = i; + b.page = i+1; + b.slot = i+2; + b.size = i+3; + + recordid * bb; + int ret = TpagedListFind(xid, list, (byte*)&a, sizeof(int), (byte**)&bb); + + assert(ret == sizeof(recordid)); + assert(!memcmp(bb, &b, sizeof(recordid))); + } + + byte * seen = calloc(NUM_ENTRIES, sizeof(byte)); + + lladd_pagedList_iterator * it = TpagedListIterator(xid, list); + + int keySize; + int valueSize; + int * key = 0; + recordid * value = 0; + + while(TpagedListNext(xid, it, (byte**)&key, &keySize, (byte**)&value, &valueSize)) { + assert(!seen[*key]); + seen[*key] = 1; + + assert(value->page == *key+1); + assert(value->slot == *key+2); + assert(value->size == *key+3); + + + free(key); + free(value); + key = 0; + value = 0; + } + + for(i = 0; i < NUM_ENTRIES; i++) { + assert(seen[i] == 1); + } + + Tcommit(xid); + Tdeinit(); + +} END_TEST + +Suite * check_suite(void) { + Suite *s = suite_create("pageOrientedList"); + /* Begin a new test */ + TCase *tc = tcase_create("pageOrientedList"); + + /* Sub tests are added, one per line, here */ + + tcase_add_test(tc, pagedListCheck); + + /* --------------------------------------------- */ + + tcase_add_checked_fixture(tc, setup, teardown); + + suite_add_tcase(s, tc); + return s; +} + +#include "../check_setup.h"