Re-implemented pageOrientedListNTA from scratch. It's now more flexible, but relies on features that are not provided by Talloc/Tdealloc, so performance isn't as good as it could be.
This commit is contained in:
parent
4d04155b0e
commit
7cf5fdee6e
9 changed files with 251 additions and 266 deletions
|
@ -43,8 +43,13 @@ terms specified in this license.
|
||||||
/**
|
/**
|
||||||
@file
|
@file
|
||||||
|
|
||||||
A linked list implementation designed to handle variable length entries, and
|
A linked list implementation designed to handle variable length
|
||||||
minimize the number of pages spanned by each list.
|
entries, and minimize the number of pages spanned by each list.
|
||||||
|
This linked list implementation is currently used to implement
|
||||||
|
buckets for the linear hash table. Unfortunately, due to
|
||||||
|
limitations in the allocation mechanisms, the full benefits of this
|
||||||
|
linked list implementation are not available to the linear hash
|
||||||
|
table.
|
||||||
|
|
||||||
The data is stored using the slotted page implementation.
|
The data is stored using the slotted page implementation.
|
||||||
|
|
||||||
|
@ -59,12 +64,23 @@ terms specified in this license.
|
||||||
#define __pageOrientedListNTA_H
|
#define __pageOrientedListNTA_H
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
//typedef struct {
|
||||||
long page;
|
// long page;
|
||||||
/* The slot of the next record to be returned. */
|
/* The slot of the next record to be returned. */
|
||||||
int slot;
|
// int slot;
|
||||||
|
//} lladd_pagedList_iterator;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
recordid headerRid;
|
||||||
|
recordid entryRid;
|
||||||
} lladd_pagedList_iterator;
|
} lladd_pagedList_iterator;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
short thisPage;
|
||||||
|
recordid nextPage;
|
||||||
|
} pagedListHeader;
|
||||||
|
|
||||||
|
|
||||||
//recordid dereferencePagedListRID(int xid, recordid rid);
|
//recordid dereferencePagedListRID(int xid, recordid rid);
|
||||||
/** @return 1 if the key was already in the list. */
|
/** @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 TpagedListInsert(int xid, recordid list, const byte * key, int keySize, const byte * value, int valueSize);
|
||||||
|
|
|
@ -143,7 +143,11 @@ recordid TallocFromPage(int xid, long page, long size) {
|
||||||
} else {
|
} else {
|
||||||
pthread_mutex_lock(&talloc_mutex);
|
pthread_mutex_lock(&talloc_mutex);
|
||||||
rid = slottedPreRallocFromPage(xid, page, size, &p);
|
rid = slottedPreRallocFromPage(xid, page, size, &p);
|
||||||
assert(p != NULL);
|
if(p == NULL) {
|
||||||
|
assert(rid.size == -1);
|
||||||
|
pthread_mutex_unlock(&talloc_mutex);
|
||||||
|
return rid;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Tupdate(xid,rid, NULL, OPERATION_ALLOC);
|
Tupdate(xid,rid, NULL, OPERATION_ALLOC);
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,13 @@
|
||||||
|
#define __USE_GNU
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
#include <pthread.h>
|
||||||
#include <lladd/transactional.h>
|
#include <lladd/transactional.h>
|
||||||
#include <lladd/hash.h>
|
#include <lladd/hash.h>
|
||||||
|
#include "../page.h"
|
||||||
|
#include "../page/slotted.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#define __USE_GNU
|
|
||||||
#include <pthread.h>
|
|
||||||
|
|
||||||
static pthread_mutex_t linear_hash_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
|
static pthread_mutex_t linear_hash_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
|
||||||
|
|
||||||
|
@ -38,7 +41,7 @@ recordid ThashCreate(int xid, int keySize, int valueSize) {
|
||||||
recordid hashHeader = Talloc(xid, sizeof(lladd_hash_header));
|
recordid hashHeader = Talloc(xid, sizeof(lladd_hash_header));
|
||||||
lladd_hash_header lhh;
|
lladd_hash_header lhh;
|
||||||
if(keySize == VARIABLE_LENGTH || valueSize == VARIABLE_LENGTH) {
|
if(keySize == VARIABLE_LENGTH || valueSize == VARIABLE_LENGTH) {
|
||||||
lhh.buckets = TarrayListAlloc(xid, HASH_INIT_ARRAY_LIST_COUNT, HASH_INIT_ARRAY_LIST_MULT, sizeof(long));
|
lhh.buckets = TarrayListAlloc(xid, HASH_INIT_ARRAY_LIST_COUNT, HASH_INIT_ARRAY_LIST_MULT, sizeof(pagedListHeader));
|
||||||
} else {
|
} else {
|
||||||
lhh.buckets = TarrayListAlloc(xid, HASH_INIT_ARRAY_LIST_COUNT, HASH_INIT_ARRAY_LIST_MULT, sizeof(lladd_linkedList_entry) + keySize + valueSize);
|
lhh.buckets = TarrayListAlloc(xid, HASH_INIT_ARRAY_LIST_COUNT, HASH_INIT_ARRAY_LIST_MULT, sizeof(lladd_linkedList_entry) + keySize + valueSize);
|
||||||
}
|
}
|
||||||
|
@ -49,7 +52,7 @@ recordid ThashCreate(int xid, int keySize, int valueSize) {
|
||||||
for(i = 0; i < HASH_INIT_ARRAY_LIST_COUNT; i++) {
|
for(i = 0; i < HASH_INIT_ARRAY_LIST_COUNT; i++) {
|
||||||
recordid rid = TpagedListAlloc(xid);
|
recordid rid = TpagedListAlloc(xid);
|
||||||
bucket.slot = i;
|
bucket.slot = i;
|
||||||
Tset(xid, bucket, &(rid.page));
|
Tset(xid, bucket, &rid);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
byte * entry = calloc(1, lhh.buckets.size);
|
byte * entry = calloc(1, lhh.buckets.size);
|
||||||
|
@ -152,9 +155,9 @@ static int __ThashInsert(int xid, recordid hashHeader, const byte* key, int keyS
|
||||||
|
|
||||||
lhh.numEntries ++;
|
lhh.numEntries ++;
|
||||||
if(lhh.keySize == VARIABLE_LENGTH || lhh.valueSize == VARIABLE_LENGTH) {
|
if(lhh.keySize == VARIABLE_LENGTH || lhh.valueSize == VARIABLE_LENGTH) {
|
||||||
/* if(lhh.numEntries > (int)((double)(lhh.nextSplit + twoToThe(lhh.bits-1)) * (HASH_FILL_FACTOR * 40))) {
|
if(lhh.numEntries > (int)((double)(lhh.nextSplit + twoToThe(lhh.bits-1)) * (HASH_FILL_FACTOR))) {
|
||||||
ThashSplitBucket(xid, hashHeader, &lhh);
|
ThashSplitBucket(xid, hashHeader, &lhh);
|
||||||
} */
|
}
|
||||||
} else {
|
} else {
|
||||||
if(lhh.numEntries > (int)((double)(lhh.nextSplit + twoToThe(lhh.bits-1)) * HASH_FILL_FACTOR)) {
|
if(lhh.numEntries > (int)((double)(lhh.nextSplit + twoToThe(lhh.bits-1)) * HASH_FILL_FACTOR)) {
|
||||||
ThashSplitBucket(xid, hashHeader, &lhh);
|
ThashSplitBucket(xid, hashHeader, &lhh);
|
||||||
|
@ -168,15 +171,15 @@ static int __ThashInsert(int xid, recordid hashHeader, const byte* key, int keyS
|
||||||
if(lhh.keySize == VARIABLE_LENGTH || lhh.valueSize == VARIABLE_LENGTH) {
|
if(lhh.keySize == VARIABLE_LENGTH || lhh.valueSize == VARIABLE_LENGTH) {
|
||||||
|
|
||||||
recordid bucketList;
|
recordid bucketList;
|
||||||
Tread(xid, bucket, &(bucketList.page));
|
Tread(xid, bucket, &bucketList);
|
||||||
bucketList.slot = 0;
|
|
||||||
bucketList.size = 0;
|
// int before = TpagedListSpansPages(xid, bucketList);
|
||||||
// int before = TpagedListSpansPages(xid, bucketList);
|
|
||||||
ret = TpagedListInsert(xid, bucketList, key, keySize, value, valueSize);
|
ret = TpagedListInsert(xid, bucketList, key, keySize, value, valueSize);
|
||||||
int after = TpagedListSpansPages(xid, bucketList);
|
// int after = TpagedListSpansPages(xid, bucketList);
|
||||||
if(after) { // Page overflowed...
|
// if(before != after) { // Page overflowed...
|
||||||
ThashSplitBucket(xid, hashHeader, &lhh);
|
// ThashSplitBucket(xid, hashHeader, &lhh);
|
||||||
}
|
// ThashSplitBucket(xid, hashHeader, &lhh);
|
||||||
|
// }
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
assert(lhh.keySize == keySize); assert(lhh.valueSize == valueSize);
|
assert(lhh.keySize == keySize); assert(lhh.valueSize == valueSize);
|
||||||
|
@ -229,9 +232,7 @@ static int __ThashRemove(int xid, recordid hashHeader, const byte * key, int key
|
||||||
int ret;
|
int ret;
|
||||||
if(lhh.keySize == VARIABLE_LENGTH || lhh.valueSize == VARIABLE_LENGTH) {
|
if(lhh.keySize == VARIABLE_LENGTH || lhh.valueSize == VARIABLE_LENGTH) {
|
||||||
recordid bucketList;
|
recordid bucketList;
|
||||||
Tread(xid, bucket, &(bucketList.page));
|
Tread(xid, bucket, &bucketList);
|
||||||
bucketList.slot = 0;
|
|
||||||
bucketList.size = 0;
|
|
||||||
ret = TpagedListRemove(xid, bucketList, key, keySize);
|
ret = TpagedListRemove(xid, bucketList, key, keySize);
|
||||||
} else {
|
} else {
|
||||||
assert(lhh.keySize == keySize);
|
assert(lhh.keySize == keySize);
|
||||||
|
@ -252,9 +253,7 @@ int ThashLookup(int xid, recordid hashHeader, const byte * key, int keySize, byt
|
||||||
int ret;
|
int ret;
|
||||||
if(lhh.keySize == VARIABLE_LENGTH || lhh.valueSize == VARIABLE_LENGTH) {
|
if(lhh.keySize == VARIABLE_LENGTH || lhh.valueSize == VARIABLE_LENGTH) {
|
||||||
recordid bucketList;
|
recordid bucketList;
|
||||||
Tread(xid, bucket, &(bucketList.page));
|
Tread(xid, bucket, &bucketList);
|
||||||
bucketList.slot = 0;
|
|
||||||
bucketList.size = 0;
|
|
||||||
ret = TpagedListFind(xid, bucketList, key, keySize, value);
|
ret = TpagedListFind(xid, bucketList, key, keySize, value);
|
||||||
} else {
|
} else {
|
||||||
assert(lhh.keySize == keySize);
|
assert(lhh.keySize == keySize);
|
||||||
|
@ -264,7 +263,7 @@ int ThashLookup(int xid, recordid hashHeader, const byte * key, int keySize, byt
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
static void ThashSplitBucket(int xid, recordid hashHeader, lladd_hash_header * lhh) {
|
static void ThashSplitBucket(int xid, recordid hashHeader, lladd_hash_header * lhh) {
|
||||||
// if(1) { return; }
|
// if(1) { return; }
|
||||||
long old_bucket = lhh->nextSplit;
|
long old_bucket = lhh->nextSplit;
|
||||||
long new_bucket = old_bucket + twoToThe(lhh->bits-1);
|
long new_bucket = old_bucket + twoToThe(lhh->bits-1);
|
||||||
recordid old_bucket_rid = lhh->buckets;
|
recordid old_bucket_rid = lhh->buckets;
|
||||||
|
@ -276,7 +275,7 @@ static void ThashSplitBucket(int xid, recordid hashHeader, lladd_hash_header * l
|
||||||
recordid new_bucket_list; // will be uninitialized if we have fixed length entries.
|
recordid new_bucket_list; // will be uninitialized if we have fixed length entries.
|
||||||
if(lhh->keySize == VARIABLE_LENGTH || lhh->valueSize == VARIABLE_LENGTH) {
|
if(lhh->keySize == VARIABLE_LENGTH || lhh->valueSize == VARIABLE_LENGTH) {
|
||||||
new_bucket_list = TpagedListAlloc(xid);
|
new_bucket_list = TpagedListAlloc(xid);
|
||||||
Tset(xid, new_bucket_rid, &(new_bucket_list.page));
|
Tset(xid, new_bucket_rid, &new_bucket_list);
|
||||||
} else {
|
} else {
|
||||||
byte * entry = calloc(1, lhh->buckets.size);
|
byte * entry = calloc(1, lhh->buckets.size);
|
||||||
Tset(xid, new_bucket_rid, entry);
|
Tset(xid, new_bucket_rid, entry);
|
||||||
|
@ -292,9 +291,8 @@ static void ThashSplitBucket(int xid, recordid hashHeader, lladd_hash_header * l
|
||||||
if(lhh->keySize == VARIABLE_LENGTH || lhh->valueSize == VARIABLE_LENGTH) {
|
if(lhh->keySize == VARIABLE_LENGTH || lhh->valueSize == VARIABLE_LENGTH) {
|
||||||
recordid old_bucket_list;
|
recordid old_bucket_list;
|
||||||
// recordid new_bucket_list;
|
// recordid new_bucket_list;
|
||||||
Tread(xid, old_bucket_rid, &(old_bucket_list.page));
|
Tread(xid, old_bucket_rid, &old_bucket_list);
|
||||||
old_bucket_list.slot = 0;
|
|
||||||
old_bucket_list.size = 0;
|
|
||||||
// Tread(xid, new_bucket_rid, &(new_bucket_list.page)); // @todo could remember value from above.
|
// Tread(xid, new_bucket_rid, &(new_bucket_list.page)); // @todo could remember value from above.
|
||||||
lladd_pagedList_iterator * pit = TpagedListIterator(xid, old_bucket_list);
|
lladd_pagedList_iterator * pit = TpagedListIterator(xid, old_bucket_list);
|
||||||
byte *key, *value;
|
byte *key, *value;
|
||||||
|
@ -363,9 +361,7 @@ int ThashNext(int xid, lladd_hash_iterator * it, byte ** key, int * keySize, byt
|
||||||
it->bucket.slot++;
|
it->bucket.slot++;
|
||||||
if(it->bucket.slot < it->numBuckets) {
|
if(it->bucket.slot < it->numBuckets) {
|
||||||
recordid bucketList;
|
recordid bucketList;
|
||||||
Tread(xid, it->bucket, &(bucketList.page));
|
Tread(xid, it->bucket, &bucketList);
|
||||||
bucketList.slot =0;
|
|
||||||
bucketList.size =0;
|
|
||||||
it->pit = TpagedListIterator(xid, bucketList);
|
it->pit = TpagedListIterator(xid, bucketList);
|
||||||
} else {
|
} else {
|
||||||
free(it);
|
free(it);
|
||||||
|
|
|
@ -1,216 +1,173 @@
|
||||||
#include <lladd/transactional.h>
|
#include <lladd/transactional.h>
|
||||||
#include "../blobManager.h"
|
|
||||||
#include "../page.h"
|
|
||||||
#include "../page/slotted.h"
|
#include <malloc.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
/**
|
|
||||||
Low level function that looks at the page structure, and finds the 'real' recordid
|
typedef struct {
|
||||||
of a page oriented list rid */
|
short nextEntry;
|
||||||
/*recordid dereferencePagedListRID(int xid, recordid rid) {
|
short keySize;
|
||||||
Page * p = loadPage(rid.page);
|
} pagedListEntry;
|
||||||
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) {
|
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 TpagedListSpansPages(int xid, recordid list) {
|
recordid NULLRID;
|
||||||
// TpagedListCompact(int xid, recordid list);
|
NULLRID.page = 0;
|
||||||
|
NULLRID.slot = 0;
|
||||||
|
NULLRID.size = -1;
|
||||||
|
|
||||||
list.slot = 0;
|
recordid ret = Talloc(xid, sizeof(pagedListHeader));
|
||||||
list.size = sizeof(long);
|
pagedListHeader header;
|
||||||
long nextPage;
|
header.thisPage = 0;
|
||||||
Tread(xid, list, &nextPage);
|
header.nextPage = NULLRID;
|
||||||
return nextPage != 0;
|
Tset(xid, ret, &header);
|
||||||
}
|
|
||||||
|
|
||||||
/** Should have write lock on page for this whole function. */
|
|
||||||
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(-1 != TpagedListFind(xid, list, key, keySize, &val)) {
|
|
||||||
free(val);
|
|
||||||
ret = 1;
|
|
||||||
int removed = TpagedListRemove(xid, list, key, keySize);
|
|
||||||
assert(removed);
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
recordid rid = TallocFromPage(xid, list.page, sizeof(long));
|
|
||||||
Tset(xid, rid, &zero);
|
|
||||||
} else {
|
|
||||||
releasePage(p);
|
|
||||||
list.page = nextPage;
|
|
||||||
p = loadPage(nextPage);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(isBlob) {
|
|
||||||
recordSize = realSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
releasePage(p);
|
|
||||||
// printf("recordsize = %d\n", recordSize);
|
|
||||||
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;
|
return ret;
|
||||||
}
|
}
|
||||||
int TpagedListFind(int xid, recordid list, const byte * key, int keySize, byte ** value) {
|
|
||||||
|
|
||||||
long nextPage = 1;
|
int TpagedListInsert(int xid, recordid list, const byte * key, int keySize, const byte * value, int valueSize) {
|
||||||
|
pagedListHeader header;
|
||||||
while (nextPage) {
|
Tread(xid, list, &header);
|
||||||
int i;
|
recordid headerRid = list;
|
||||||
|
|
||||||
Page * p = loadPage(list.page);
|
byte * garbage;
|
||||||
|
int ret = (TpagedListFind(xid, list, key, keySize, &garbage) != -1);
|
||||||
// int pageCount = TrecordsInPage(xid, list.page);
|
if(ret) {
|
||||||
int pageCount = *numslots_ptr(p);
|
TpagedListRemove(xid, list, key, keySize);
|
||||||
|
free(garbage);
|
||||||
// printf("%ld\n", nextPage);
|
}
|
||||||
//fflush(stdout);
|
int entrySize = sizeof(pagedListEntry) + keySize + valueSize;
|
||||||
|
|
||||||
for(i = 1; i < pageCount; i++) {
|
recordid rid = TallocFromPage(xid, headerRid.page, entrySize);
|
||||||
recordid entry = list;
|
DEBUG("Alloced rid: {%d %d %d}", rid.page, rid.slot, rid.size);
|
||||||
entry.slot = i;
|
|
||||||
// int length = TrecordSize(xid, entry);
|
// When the loop completes, header will contain the contents of the page header the entry will be inserted into,
|
||||||
int length = getRecordSize(xid,p,entry);
|
// headerrid will contain the rid of that header, and rid will contain the newly allocated recordid
|
||||||
if(length != -1) { // then entry is defined.
|
while(rid.size == -1) {
|
||||||
short * dat = malloc(length);
|
if(header.nextPage.size == -1) {
|
||||||
entry.size = length;
|
header.nextPage = Talloc(xid, sizeof(pagedListHeader));
|
||||||
// Tread(xid, entry, dat);
|
DEBUG("allocing on new page %d\n", header.nextPage.page);
|
||||||
slottedRead(xid, p, entry, (byte*)dat);
|
Tset(xid, headerRid, &header);
|
||||||
if(*dat == keySize && !memcmp(dat+1, key, keySize)) {
|
pagedListHeader newHead;
|
||||||
int valueSize = length-keySize-sizeof(short);
|
newHead.thisPage = 0;
|
||||||
*value = malloc(valueSize);
|
newHead.nextPage.page =0;
|
||||||
|
newHead.nextPage.slot =0;
|
||||||
memcpy(*value, ((byte*)(dat+1))+keySize, valueSize);
|
newHead.nextPage.size =-1;
|
||||||
|
Tset(xid, header.nextPage, &newHead);
|
||||||
free(dat);
|
|
||||||
releasePage(p);
|
|
||||||
return valueSize;
|
|
||||||
}
|
|
||||||
free(dat);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
headerRid = header.nextPage;
|
||||||
|
Tread(xid, header.nextPage, &header);
|
||||||
|
rid = TallocFromPage(xid, headerRid.page, entrySize);
|
||||||
|
DEBUG("Alloced rid: {%d %d %d}", rid.page, rid.slot, rid.size);
|
||||||
|
}
|
||||||
|
|
||||||
// recordid rid = list;
|
pagedListEntry * dat = malloc(entrySize);
|
||||||
|
|
||||||
|
dat->keySize = keySize;
|
||||||
|
dat->nextEntry = header.thisPage;
|
||||||
|
memcpy(dat+1, key, keySize);
|
||||||
|
memcpy(((byte*)(dat+1))+keySize, value, valueSize);
|
||||||
|
Tset(xid, rid, dat);
|
||||||
|
|
||||||
|
header.thisPage = rid.slot;
|
||||||
|
DEBUG("Header.thisPage = %d\n", rid.slot);
|
||||||
|
Tset(xid, headerRid, &header);
|
||||||
|
free(dat);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int TpagedListFind(int xid, recordid list, const byte * key, int keySize, byte ** value) {
|
||||||
|
pagedListHeader header;
|
||||||
|
Tread(xid, list, &header);
|
||||||
|
|
||||||
|
recordid rid;
|
||||||
|
rid.page = list.page;
|
||||||
|
rid.slot = header.thisPage;
|
||||||
|
|
||||||
|
while(rid.slot || header.nextPage.size != -1) {
|
||||||
|
rid.size = TrecordSize(xid, rid);
|
||||||
|
|
||||||
|
pagedListEntry * dat = malloc(rid.size);
|
||||||
|
Tread(xid, rid, dat);
|
||||||
|
|
||||||
list.slot = 0;
|
if(!memcmp(dat+1, key, keySize)) {
|
||||||
list.size = sizeof(long);
|
int valueSize = rid.size - keySize - sizeof(pagedListEntry);
|
||||||
|
*value = malloc(valueSize);
|
||||||
|
memcpy(*value, ((byte*)(dat+1))+keySize, valueSize);
|
||||||
|
free(dat);
|
||||||
|
return valueSize;
|
||||||
|
}
|
||||||
|
if(dat->nextEntry) { // another entry on this page
|
||||||
|
rid.slot = dat->nextEntry;
|
||||||
|
} else if (header.nextPage.size != -1) { // another page
|
||||||
|
rid.page = header.nextPage.page;
|
||||||
|
Tread(xid, header.nextPage, &header);
|
||||||
|
rid.slot = header.thisPage;
|
||||||
|
} else { // we've reached the end of the last page
|
||||||
|
rid.slot = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(dat);
|
||||||
|
}
|
||||||
|
|
||||||
// Tread(xid, list, &nextPage);
|
|
||||||
slottedRead(xid, p, list, (byte*)&nextPage);
|
|
||||||
|
|
||||||
list.page = nextPage;
|
|
||||||
|
|
||||||
releasePage(p);
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int TpagedListRemove(int xid, recordid list, const byte * key, int keySize) {
|
int TpagedListRemove(int xid, recordid list, const byte * key, int keySize) {
|
||||||
long nextPage = 1;
|
pagedListHeader header;
|
||||||
|
Tread(xid, list, &header);
|
||||||
while (nextPage) {
|
recordid headerRid;
|
||||||
int i;
|
recordid rid;
|
||||||
|
rid.page = list.page;
|
||||||
|
rid.slot = header.thisPage;
|
||||||
|
short lastSlot = -1;
|
||||||
|
headerRid = list;
|
||||||
|
while(rid.slot || header.nextPage.size != -1) {
|
||||||
|
rid.size = TrecordSize(xid, rid);
|
||||||
|
pagedListEntry * dat = malloc(rid.size);
|
||||||
|
Tread(xid, rid, dat);
|
||||||
|
|
||||||
|
if(!memcmp(dat+1, key, keySize)) {
|
||||||
|
|
||||||
Page * p = loadPage(list.page);
|
if(lastSlot != -1) {
|
||||||
|
recordid lastRid = rid;
|
||||||
// int pageCount = TrecordsInPage(xid, list.page);
|
lastRid.slot = lastSlot;
|
||||||
int pageCount = *numslots_ptr(p);
|
lastRid.size = TrecordSize(xid, lastRid);
|
||||||
|
pagedListEntry * lastRidBuf = malloc(lastRid.size);
|
||||||
// printf("%ld\n", nextPage);
|
Tread(xid, lastRid, lastRidBuf);
|
||||||
fflush(stdout);
|
lastRidBuf->nextEntry = dat->nextEntry;
|
||||||
|
Tset(xid, lastRid, lastRidBuf);
|
||||||
for(i = 1; i < pageCount; i++) {
|
free(lastRidBuf);
|
||||||
recordid entry = list;
|
} else {
|
||||||
entry.slot = i;
|
header.thisPage = dat->nextEntry;
|
||||||
// int length = TrecordSize(xid, entry);
|
Tset(xid, headerRid, &header);
|
||||||
int length = getRecordSize(xid, p, entry);
|
|
||||||
if(length != -1) { // then entry is defined.
|
|
||||||
short * dat = malloc(length);
|
|
||||||
entry.size = length;
|
|
||||||
|
|
||||||
slottedRead(xid,p,entry,(byte*)dat);
|
|
||||||
|
|
||||||
// Tread(xid, entry, dat);
|
|
||||||
|
|
||||||
if(*dat == keySize && !memcmp(dat+1, key, keySize)) {
|
|
||||||
releasePage(p);
|
|
||||||
Tdealloc(xid, entry);
|
|
||||||
// assert(-1 == TrecordSize(xid, entry));
|
|
||||||
free(dat);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
free(dat);
|
|
||||||
}
|
}
|
||||||
|
Tdealloc(xid, rid);
|
||||||
|
free(dat);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if(dat->nextEntry) { // another entry on this page
|
||||||
|
lastSlot = rid.slot;
|
||||||
|
rid.slot = dat->nextEntry;
|
||||||
|
} else if (header.nextPage.size != -1) { // another page
|
||||||
|
lastSlot = -1;
|
||||||
|
rid.page = header.nextPage.page;
|
||||||
|
headerRid = header.nextPage;
|
||||||
|
Tread(xid, header.nextPage, &header);
|
||||||
|
rid.slot = header.thisPage;
|
||||||
|
} else { // we've reached the end of the last page
|
||||||
|
rid.slot = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
list.slot = 0;
|
free(dat);
|
||||||
list.size = sizeof(long);
|
}
|
||||||
|
|
||||||
// Tread(xid, list, &nextPage);
|
|
||||||
slottedRead(xid,p,list, (byte*)&nextPage);
|
|
||||||
|
|
||||||
list.page = nextPage;
|
|
||||||
releasePage(p);
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
int TpagedListMove(int xid, recordid start_list, recordid end_list, const byte *key, int keySize) {
|
|
||||||
|
int TpagedListMove(int xid, recordid start_list, recordid end_list, const byte * key, int keySize) {
|
||||||
byte * value;
|
byte * value;
|
||||||
int valueSize = TpagedListFind(xid, start_list, key, keySize, &value);
|
int valueSize = TpagedListFind(xid, start_list, key, keySize, &value);
|
||||||
if(valueSize != -1) {
|
if(valueSize != -1) {
|
||||||
|
@ -225,57 +182,54 @@ int TpagedListMove(int xid, recordid start_list, recordid end_list, const byte *
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lladd_pagedList_iterator * TpagedListIterator(int xid, recordid list) {
|
lladd_pagedList_iterator * TpagedListIterator(int xid, recordid list) {
|
||||||
lladd_pagedList_iterator * ret = malloc(sizeof(lladd_pagedList_iterator));
|
pagedListHeader header;
|
||||||
|
Tread(xid, list, &header);
|
||||||
|
lladd_pagedList_iterator * it = malloc(sizeof(lladd_pagedList_iterator));
|
||||||
|
|
||||||
ret->page = list.page;
|
it->headerRid = header.nextPage;
|
||||||
ret->slot = 1;
|
it->entryRid = list;
|
||||||
|
// printf("slot <- %d\n", header.thisPage);
|
||||||
|
it->entryRid.slot = header.thisPage;
|
||||||
|
|
||||||
return ret;
|
return it;
|
||||||
}
|
}
|
||||||
|
|
||||||
int TpagedListNext(int xid, lladd_pagedList_iterator * it,
|
int TpagedListNext(int xid, lladd_pagedList_iterator * it,
|
||||||
byte ** key, int * keySize,
|
byte ** key, int * keySize,
|
||||||
byte ** value, int * valueSize) {
|
byte ** value, int * valueSize) {
|
||||||
// printf("next: page %d slot %d\n", it->page, it->slot);
|
while(it->entryRid.slot || it->headerRid.size != -1) {
|
||||||
recordid rid;
|
if(it->entryRid.slot) {
|
||||||
while(it->page) {
|
it->entryRid.size = TrecordSize(xid, it->entryRid);
|
||||||
while(it->slot < TrecordsInPage(xid, it->page)) {
|
assert(it->entryRid.size != -1);
|
||||||
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);
|
pagedListEntry * entry = malloc(it->entryRid.size);
|
||||||
*value = malloc(*valueSize);
|
|
||||||
|
Tread(xid, it->entryRid, entry);
|
||||||
|
|
||||||
|
*keySize = entry->keySize;
|
||||||
|
*valueSize = it->entryRid.size - *keySize - sizeof(pagedListEntry);
|
||||||
|
|
||||||
memcpy(*key, ((short*)dat)+1, *keySize);
|
*key = malloc(*keySize);
|
||||||
memcpy(*value, ((byte*)(((short*)dat)+1)) + *keySize, *valueSize);
|
*value = malloc(*valueSize);
|
||||||
|
|
||||||
free(dat);
|
memcpy(*key, entry+1, *keySize);
|
||||||
it->slot++;
|
memcpy(*value, ((byte*)(entry+1))+*keySize, *valueSize);
|
||||||
return 1;
|
|
||||||
}
|
it->entryRid.slot = entry->nextEntry;
|
||||||
it->slot++;
|
// printf("slotA <- %d\n", it->entryRid.slot);
|
||||||
|
|
||||||
|
free(entry);
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
} else { // move to next page.
|
||||||
|
pagedListHeader header;
|
||||||
|
Tread(xid, it->headerRid, &header);
|
||||||
|
it->entryRid.page = it->headerRid.page;
|
||||||
|
it->headerRid = header.nextPage;
|
||||||
|
it->entryRid.slot = header.thisPage;
|
||||||
|
// printf("slotB <- %d\n", it->entryRid.slot);
|
||||||
}
|
}
|
||||||
rid.page = it->page;
|
|
||||||
rid.slot = 0;
|
|
||||||
rid.size = sizeof(long);
|
|
||||||
Tread(xid, rid, &(it->page));
|
|
||||||
it->slot = 1;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
free(it);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,8 @@ increase the available free space.
|
||||||
|
|
||||||
The caller of this function must have a writelock on the page.
|
The caller of this function must have a writelock on the page.
|
||||||
*/
|
*/
|
||||||
static void slottedCompact(Page * page) {
|
|
||||||
|
void slottedCompact(Page * page) {
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
Page bufPage;
|
Page bufPage;
|
||||||
|
@ -192,7 +193,16 @@ recordid slottedPreRallocFromPage(int xid, long page, long size, Page **pp) {
|
||||||
|
|
||||||
*pp = loadPage(page);
|
*pp = loadPage(page);
|
||||||
|
|
||||||
assert(slottedFreespace(*pp) >= size);
|
if(slottedFreespace(*pp) < size) {
|
||||||
|
releasePage(*pp);
|
||||||
|
*pp = NULL;
|
||||||
|
recordid rid;
|
||||||
|
rid.page = 0;
|
||||||
|
rid.slot = 0;
|
||||||
|
rid.size = -1;
|
||||||
|
return rid;
|
||||||
|
}
|
||||||
|
|
||||||
if(*page_type_ptr(*pp) == UNINITIALIZED_PAGE) {
|
if(*page_type_ptr(*pp) == UNINITIALIZED_PAGE) {
|
||||||
slottedPageInitialize(*pp);
|
slottedPageInitialize(*pp);
|
||||||
}
|
}
|
||||||
|
|
|
@ -206,3 +206,5 @@ int slottedGetType(Page * p, int slot);
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void slottedSetType(Page * p, int slot, int type);
|
void slottedSetType(Page * p, int slot, int type);
|
||||||
|
/** The caller of this function must have a write lock on the page. */
|
||||||
|
void slottedCompact(Page * page);
|
||||||
|
|
|
@ -6,6 +6,6 @@ else
|
||||||
TESTS =
|
TESTS =
|
||||||
endif
|
endif
|
||||||
noinst_PROGRAMS = $(TESTS)
|
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
|
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 check_pageOrientedListNTA.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
|
AM_CFLAGS= -g -Wall -pedantic -std=gnu99
|
||||||
|
|
|
@ -130,9 +130,12 @@ START_TEST(linearHashNTAVariableSizetest)
|
||||||
val.page = i * NUM_ENTRIES;
|
val.page = i * NUM_ENTRIES;
|
||||||
val.slot = val.page * NUM_ENTRIES;
|
val.slot = val.page * NUM_ENTRIES;
|
||||||
val.size = val.slot * NUM_ENTRIES;
|
val.size = val.slot * NUM_ENTRIES;
|
||||||
|
val2 = 0;
|
||||||
assert(-1 == ThashLookup(xid, hashHeader, (byte*)&i, sizeof(int), (byte**)&val2));
|
assert(-1 == ThashLookup(xid, hashHeader, (byte*)&i, sizeof(int), (byte**)&val2));
|
||||||
ThashInsert(xid, hashHeader, (byte*)&i, sizeof(int), (byte*)&val, sizeof(recordid));
|
ThashInsert(xid, hashHeader, (byte*)&i, sizeof(int), (byte*)&val, sizeof(recordid));
|
||||||
assert(sizeof(recordid) == ThashLookup(xid, hashHeader, (byte*)&i, sizeof(int), (byte**)&val2));
|
val2 =0;
|
||||||
|
int ret = ThashLookup(xid, hashHeader, (byte*)&i, sizeof(int), (byte**)&val2);
|
||||||
|
assert(sizeof(recordid) == ret);
|
||||||
assert(val2->page == i * NUM_ENTRIES);
|
assert(val2->page == i * NUM_ENTRIES);
|
||||||
assert(val2->slot == val2->page * NUM_ENTRIES);
|
assert(val2->slot == val2->page * NUM_ENTRIES);
|
||||||
assert(val2->size == val2->slot * NUM_ENTRIES);
|
assert(val2->size == val2->slot * NUM_ENTRIES);
|
||||||
|
|
|
@ -116,7 +116,7 @@ START_TEST(pagedListCheck) {
|
||||||
|
|
||||||
ret = TpagedListFind(xid, list, (byte*)&a, sizeof(int), (byte**)&bb);
|
ret = TpagedListFind(xid, list, (byte*)&a, sizeof(int), (byte**)&bb);
|
||||||
|
|
||||||
assert(!ret);
|
assert(-1==ret);
|
||||||
assert(!bb);
|
assert(!bb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue