Error handling for linked list.

This commit is contained in:
Sears Russell 2005-02-22 23:11:03 +00:00
parent 41fb85eef0
commit 29dacbe7ed
2 changed files with 217 additions and 162 deletions

View file

@ -29,23 +29,23 @@ typedef struct {
recordid listRoot; recordid listRoot;
} lladd_linkedList_iterator; } lladd_linkedList_iterator;
int TlinkedListInsert(int xid, recordid list, const byte * key, int keySize, const byte * value, int valueSize); compensated_function int TlinkedListInsert(int xid, recordid list, const byte * key, int keySize, const byte * value, int valueSize);
int TlinkedListFind(int xid, recordid list, const byte * key, int keySize, byte ** value); compensated_function int TlinkedListFind(int xid, recordid list, const byte * key, int keySize, byte ** value);
int TlinkedListRemove(int xid, recordid list, const byte * key, int keySize); compensated_function int TlinkedListRemove(int xid, recordid list, const byte * key, int keySize);
int TlinkedListMove(int xid, recordid start_list, recordid end_list, const byte *key, int keySize); compensated_function int TlinkedListMove(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 /** The linked list iterator can tolerate the concurrent removal of values that
it has already returned. In the presence of such removals, the iterator 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() will return the keys and values present in the list as it existed when next()
was first called. was first called.
@return a new iterator initialized to the head of the list. */ @return a new iterator initialized to the head of the list. */
lladd_linkedList_iterator * TlinkedListIterator(int xid, recordid list, int keySize, int valueSize); compensated_function lladd_linkedList_iterator * TlinkedListIterator(int xid, recordid list, int keySize, int valueSize);
/** @return 1 if there was another entry to be iterated over. 0 otherwise. /** @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 If this function returns 1, the caller must free() the malloced memory
returned via the key and value arguments.*/ returned via the key and value arguments.*/
int TlinkedListNext(int xid, lladd_linkedList_iterator * it, byte ** key, int * keySize, byte ** value, int * valueSize); compensated_function int TlinkedListNext(int xid, lladd_linkedList_iterator * it, byte ** key, int * keySize, byte ** value, int * valueSize);
recordid TlinkedListCreate(int xid, int keySize, int ValueSize); compensated_function recordid TlinkedListCreate(int xid, int keySize, int ValueSize);
void TlinkedListDelete(int xid, recordid list); compensated_function void TlinkedListDelete(int xid, recordid list);
Operation getLinkedListInsert(); Operation getLinkedListInsert();
Operation getLinkedListRemove(); Operation getLinkedListRemove();
#endif //__LINKED_LIST_NTA_H #endif //__LINKED_LIST_NTA_H

View file

@ -43,8 +43,8 @@
static pthread_mutex_t linked_list_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; static pthread_mutex_t linked_list_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
static void __TlinkedListInsert(int xid, recordid list, const byte * key, int keySize, const byte * value, int valueSize); compensated_function static void __TlinkedListInsert(int xid, recordid list, const byte * key, int keySize, const byte * value, int valueSize);
static int __TlinkedListRemove(int xid, recordid list, const byte * key, int keySize); compensated_function static int __TlinkedListRemove(int xid, recordid list, const byte * key, int keySize);
typedef struct { typedef struct {
recordid list; recordid list;
int keySize; int keySize;
@ -67,12 +67,14 @@ compensated_function static int operateInsert(int xid, Page *p, lsn_t lsn, reco
valueSize = log->valueSize; valueSize = log->valueSize;
key = (byte*)(log+1); key = (byte*)(log+1);
value = ((byte*)(log+1))+keySize; value = ((byte*)(log+1))+keySize;
pthread_mutex_lock(&linked_list_mutex); begin_action_ret(pthread_mutex_unlock, &linked_list_mutex, compensation_error()) {
pthread_mutex_lock(&linked_list_mutex);
// printf("Operate insert called: rid.page = %d keysize = %d valuesize = %d %d {%d %d %d}\n", rid.page, log->keySize, log->valueSize, *(int*)key, value->page, value->slot, value->size); // printf("Operate insert called: rid.page = %d keysize = %d valuesize = %d %d {%d %d %d}\n", rid.page, log->keySize, log->valueSize, *(int*)key, value->page, value->slot, value->size);
// Skip writing the undo! Recovery will write a CLR after we're done, effectively // Skip writing the undo! Recovery will write a CLR after we're done, effectively
// wrapping this in a nested top action, so we needn't worry about that either. // wrapping this in a nested top action, so we needn't worry about that either.
__TlinkedListInsert(xid, log->list, key, keySize, value, valueSize); __TlinkedListInsert(xid, log->list, key, keySize, value, valueSize);
pthread_mutex_unlock(&linked_list_mutex); } compensate_ret(compensation_error());
// pthread_mutex_unlock(&linked_list_mutex);
return 0; return 0;
} }
@ -85,16 +87,21 @@ compensated_function static int operateRemove(int xid, Page *p, lsn_t lsn, reco
keySize = log->keySize; keySize = log->keySize;
key = (byte*)(log+1); key = (byte*)(log+1);
pthread_mutex_lock(&linked_list_mutex); begin_action_ret(pthread_mutex_unlock, &linked_list_mutex, compensation_error()) {
// printf("Operate remove called: %d\n", *(int*)key); pthread_mutex_lock(&linked_list_mutex);
// Don't call the version that writes an undo entry! // printf("Operate remove called: %d\n", *(int*)key);
__TlinkedListRemove(xid, log->list, key, keySize); // Don't call the version that writes an undo entry!
pthread_mutex_unlock(&linked_list_mutex); __TlinkedListRemove(xid, log->list, key, keySize);
} compensate_ret(compensation_error());
// pthread_mutex_unlock(&linked_list_mutex);
return 0; return 0;
} }
int TlinkedListInsert(int xid, recordid list, const byte * key, int keySize, const byte * value, int valueSize) { compensated_function int TlinkedListInsert(int xid, recordid list, const byte * key, int keySize, const byte * value, int valueSize) {
int ret = TlinkedListRemove(xid, list, key, keySize); int ret;
try_ret(compensation_error()) {
ret = TlinkedListRemove(xid, list, key, keySize);
} end_ret(compensation_error());
lladd_linkedListInsert_log * undoLog = malloc(sizeof(lladd_linkedListInsert_log) + keySize); lladd_linkedListInsert_log * undoLog = malloc(sizeof(lladd_linkedListInsert_log) + keySize);
@ -102,13 +109,15 @@ int TlinkedListInsert(int xid, recordid list, const byte * key, int keySize, con
undoLog->keySize = keySize; undoLog->keySize = keySize;
memcpy(undoLog+1, key, keySize); memcpy(undoLog+1, key, keySize);
pthread_mutex_lock(&linked_list_mutex); pthread_mutex_lock(&linked_list_mutex);
void * handle = TbeginNestedTopAction(xid, OPERATION_LINKED_LIST_INSERT, begin_action_ret(pthread_mutex_unlock, &linked_list_mutex, compensation_error()) {
(byte*)undoLog, sizeof(lladd_linkedListInsert_log) + keySize); void * handle = TbeginNestedTopAction(xid, OPERATION_LINKED_LIST_INSERT,
free(undoLog); (byte*)undoLog, sizeof(lladd_linkedListInsert_log) + keySize);
__TlinkedListInsert(xid, list, key, keySize, value, valueSize); free(undoLog);
__TlinkedListInsert(xid, list, key, keySize, value, valueSize);
TendNestedTopAction(xid, handle);
TendNestedTopAction(xid, handle); } compensate_ret(compensation_error());
pthread_mutex_unlock(&linked_list_mutex); // pthread_mutex_unlock(&linked_list_mutex);
return ret; return ret;
} }
@ -131,8 +140,8 @@ Operation getLinkedListRemove() {
}; };
return o; return o;
} }
static void __TlinkedListInsert(int xid, recordid list, const byte * key, int keySize, const byte * value, int valueSize) { compensated_function static void __TlinkedListInsert(int xid, recordid list, const byte * key, int keySize, const byte * value, int valueSize) {
//int ret = TlinkedListRemove(xid, list, key, keySize); //int ret = Tli nkedListRemove(xid, list, key, keySize);
try { try {
@ -161,7 +170,7 @@ static void __TlinkedListInsert(int xid, recordid list, const byte * key, int ke
} end; } end;
} }
int TlinkedListFind(int xid, recordid list, const byte * key, int keySize, byte ** value) { compensated_function int TlinkedListFind(int xid, recordid list, const byte * key, int keySize, byte ** value) {
lladd_linkedList_entry * entry = malloc(list.size); lladd_linkedList_entry * entry = malloc(list.size);
@ -205,43 +214,52 @@ int TlinkedListFind(int xid, recordid list, const byte * key, int keySize, byte
int TlinkedListRemove(int xid, recordid list, const byte * key, int keySize) { compensated_function int TlinkedListRemove(int xid, recordid list, const byte * key, int keySize) {
byte * value; byte * value;
int valueSize; int valueSize;
pthread_mutex_lock(&linked_list_mutex); pthread_mutex_lock(&linked_list_mutex);
int ret = TlinkedListFind(xid, list, key, keySize, &value); int ret;
begin_action_ret(pthread_mutex_unlock, &linked_list_mutex, compensation_error()) {
ret = TlinkedListFind(xid, list, key, keySize, &value);
} end_action_ret(compensation_error());
if(ret != -1) { if(ret != -1) {
valueSize = ret; valueSize = ret;
} else { } else {
pthread_mutex_unlock(&linked_list_mutex); pthread_mutex_unlock(&linked_list_mutex);
return 0; return 0;
} }
int entrySize = sizeof(lladd_linkedListRemove_log) + keySize + valueSize; begin_action_ret(pthread_mutex_unlock, &linked_list_mutex, compensation_error()) {
lladd_linkedListRemove_log * undoLog = malloc(entrySize); int entrySize = sizeof(lladd_linkedListRemove_log) + keySize + valueSize;
lladd_linkedListRemove_log * undoLog = malloc(entrySize);
undoLog->list = list; undoLog->list = list;
undoLog->keySize = keySize; undoLog->keySize = keySize;
undoLog->valueSize = valueSize; undoLog->valueSize = valueSize;
memcpy(undoLog+1, key, keySize); memcpy(undoLog+1, key, keySize);
memcpy(((byte*)(undoLog+1))+keySize, value, valueSize); memcpy(((byte*)(undoLog+1))+keySize, value, valueSize);
// printf("entry size %d sizeof(remove_log)%d keysize %d valuesize %d sizeof(rid) %d key %d value {%d %d %ld}\n", // printf("entry size %d sizeof(remove_log)%d keysize %d valuesize %d sizeof(rid) %d key %d value {%d %d %ld}\n",
// entrySize, sizeof(lladd_linkedListRemove_log), keySize, valueSize, sizeof(recordid), key, value->page, value->slot, value->size); // entrySize, sizeof(lladd_linkedListRemove_log), keySize, valueSize, sizeof(recordid), key, value->page, value->slot, value->size);
void * handle = TbeginNestedTopAction(xid, OPERATION_LINKED_LIST_REMOVE, void * handle = TbeginNestedTopAction(xid, OPERATION_LINKED_LIST_REMOVE,
(byte*)undoLog, entrySize); (byte*)undoLog, entrySize);
free(value); free(value);
free(undoLog); free(undoLog);
__TlinkedListRemove(xid, list, key, keySize); __TlinkedListRemove(xid, list, key, keySize);
TendNestedTopAction(xid, handle);
} compensate_ret(compensation_error());
TendNestedTopAction(xid, handle);
pthread_mutex_unlock(&linked_list_mutex);
return 1; return 1;
} }
static int __TlinkedListRemove(int xid, recordid list, const byte * key, int keySize) { compensated_function static int __TlinkedListRemove(int xid, recordid list, const byte * key, int keySize) {
lladd_linkedList_entry * entry = malloc(list.size); lladd_linkedList_entry * entry = malloc(list.size);
pthread_mutex_lock(&linked_list_mutex); pthread_mutex_lock(&linked_list_mutex);
Tread(xid, list, entry);
begin_action_ret(pthread_mutex_unlock, &linked_list_mutex, compensation_error()) {
Tread(xid, list, entry);
} end_action_ret(compensation_error());
if(entry->next.size == 0) { if(entry->next.size == 0) {
//Empty List. //Empty List.
free(entry); free(entry);
@ -252,93 +270,114 @@ static int __TlinkedListRemove(int xid, recordid list, const byte * key, int key
recordid lastRead = list; recordid lastRead = list;
recordid oldLastRead; recordid oldLastRead;
oldLastRead.size = -2; oldLastRead.size = -2;
while(1) { int ret = 0;
if(!memcmp(entry + 1, key, keySize)) {
// Bucket contains the entry of interest. begin_action_ret(pthread_mutex_unlock, &linked_list_mutex, compensation_error()) {
if(listRoot) {
if(entry->next.size == -1) { while(1) {
memset(entry, 0, list.size); if(compensation_error()) { break; }
Tset(xid, lastRead, entry); if(!memcmp(entry + 1, key, keySize)) {
} else { // Bucket contains the entry of interest.
assert(entry->next.size == list.size); // Otherwise, sometihng strange is happening, or the list contains entries with variable sizes. if(listRoot) {
lladd_linkedList_entry * entry2 = malloc(list.size); if(entry->next.size == -1) {
Tread(xid, entry->next, entry2); memset(entry, 0, list.size);
Tdealloc(xid, entry->next); // could break iterator, since it writes one entry ahead. Tset(xid, lastRead, entry);
Tset(xid, lastRead, entry2); } else {
free(entry2); assert(entry->next.size == list.size); // Otherwise, something strange is happening, or the list contains entries with variable sizes.
lladd_linkedList_entry * entry2 = malloc(list.size);
Tread(xid, entry->next, entry2);
Tdealloc(xid, entry->next); // could break iterator, since it writes one entry ahead.
Tset(xid, lastRead, entry2);
free(entry2);
} }
} else { } else {
lladd_linkedList_entry * entry2 = malloc(list.size); lladd_linkedList_entry * entry2 = malloc(list.size);
assert(oldLastRead.size != -2); assert(oldLastRead.size != -2);
Tread(xid, oldLastRead, entry2); Tread(xid, oldLastRead, entry2);
memcpy(&(entry2->next), &(entry->next), sizeof(recordid)); memcpy(&(entry2->next), &(entry->next), sizeof(recordid));
Tset(xid, oldLastRead, entry2); Tset(xid, oldLastRead, entry2);
Tdealloc(xid, lastRead); Tdealloc(xid, lastRead);
free (entry2); free (entry2);
} }
free(entry); // free(entry);
pthread_mutex_unlock(&linked_list_mutex); // pthread_mutex_unlock(&linked_list_mutex);
return 1; // return 1;
} else { // Entry doesn't match the key we're looking for. ret = 1;
if(entry->next.size != -1) { break;
assert(entry->next.size == list.size); // Don't handle lists with variable length records for now } else { // Entry doesn't match the key we're looking for.
oldLastRead = lastRead; if(entry->next.size != -1) {
lastRead = entry->next; assert(entry->next.size == list.size); // Don't handle lists with variable length records for now
Tread(xid, entry->next, entry); oldLastRead = lastRead;
listRoot = 0; lastRead = entry->next;
} else { Tread(xid, entry->next, entry);
break; listRoot = 0;
} else {
break;
}
} }
} }
} free(entry);
free(entry); } compensate_ret(compensation_error());
pthread_mutex_unlock(&linked_list_mutex);
return 0;
}
/*** @todo TlinkedListMove could be much faster, but this is good enough for a first pass */
int TlinkedListMove(int xid, recordid start_list, recordid end_list, const byte *key, int keySize) {
byte * value;
pthread_mutex_lock(&linked_list_mutex);
int valueSize = TlinkedListFind(xid, start_list, key, keySize, &value);
if(valueSize == -1) {
pthread_mutex_unlock(&linked_list_mutex);
return 0;
} else {
TlinkedListRemove(xid, start_list, key, keySize);
TlinkedListInsert(xid, end_list, key, keySize, value, valueSize);
free(value);
pthread_mutex_unlock(&linked_list_mutex);
return 1;
}
}
recordid TlinkedListCreate(int xid, int keySize, int valueSize) {
recordid ret = Talloc(xid, sizeof(lladd_linkedList_entry) + keySize + valueSize);
byte * cleared = calloc(sizeof(lladd_linkedList_entry) + keySize + valueSize, sizeof(byte));
Tset(xid, ret, cleared);
free(cleared);
return ret; return ret;
} }
void TlinkedListDelete(int xid, recordid list) { /*** @todo TlinkedListMove could be much faster, but this is good enough for a first pass */
lladd_linkedList_entry * entry = malloc(list.size); compensated_function int TlinkedListMove(int xid, recordid start_list, recordid end_list, const byte *key, int keySize) {
byte * value = 0;
int ret;
begin_action_ret(pthread_mutex_unlock, &linked_list_mutex, compensation_error()) {
pthread_mutex_lock(&linked_list_mutex);
int valueSize = TlinkedListFind(xid, start_list, key, keySize, &value);
if(valueSize != -1) {
// pthread_mutex_unlock(&linked_list_mutex);
// return 0;
ret = 0;
} else {
TlinkedListRemove(xid, start_list, key, keySize);
TlinkedListInsert(xid, end_list, key, keySize, value, valueSize);
// pthread_mutex_unlock(&linked_list_mutex);
// return 1;
ret = 1;
}
if(value) { free(value); }
} compensate_ret(compensation_error());
Tread(xid, list, entry); return ret;
Tdealloc(xid, list); }
compensated_function recordid TlinkedListCreate(int xid, int keySize, int valueSize) {
recordid ret;
try_ret(NULLRID) {
ret = Talloc(xid, sizeof(lladd_linkedList_entry) + keySize + valueSize);
byte * cleared = calloc(sizeof(lladd_linkedList_entry) + keySize + valueSize, sizeof(byte));
Tset(xid, ret, cleared);
free(cleared);
} end_ret(NULLRID);
return ret;
}
compensated_function void TlinkedListDelete(int xid, recordid list) {
try {
lladd_linkedList_entry * entry = malloc(list.size);
if(entry->next.size == 0) { Tread(xid, list, entry);
return; Tdealloc(xid, list);
}
while(entry->next.size != -1) { if(entry->next.size == 0) {
recordid nextEntry; return;
Tread(xid, nextEntry, entry); }
assert(!memcmp(&nextEntry, &(entry->next), sizeof(recordid)));
Tdealloc(xid, nextEntry);
}
free(entry); while(entry->next.size != -1) {
if(compensation_error()) { break; }
recordid nextEntry;
Tread(xid, nextEntry, entry);
assert(!memcmp(&nextEntry, &(entry->next), sizeof(recordid)));
Tdealloc(xid, nextEntry);
}
free(entry);
} end;
} }
lladd_linkedList_iterator * TlinkedListIterator(int xid, recordid list, int keySize, int valueSize) { compensated_function lladd_linkedList_iterator * TlinkedListIterator(int xid, recordid list, int keySize, int valueSize) {
lladd_linkedList_iterator * it = malloc(sizeof(lladd_linkedList_iterator)); lladd_linkedList_iterator * it = malloc(sizeof(lladd_linkedList_iterator));
it->keySize = keySize; it->keySize = keySize;
it->valueSize = valueSize; it->valueSize = valueSize;
@ -348,36 +387,51 @@ lladd_linkedList_iterator * TlinkedListIterator(int xid, recordid list, int keyS
return it; return it;
} }
int TlinkedListNext(int xid, lladd_linkedList_iterator * it, byte ** key, int * keySize, byte **value, int * valueSize) { compensated_function int TlinkedListNext(int xid, lladd_linkedList_iterator * it, byte ** key, int * keySize, byte **value, int * valueSize) {
if(it->next.size == -1) { free(it); return 0; } if(it->next.size == -1) { free(it); return 0; }
pthread_mutex_lock(&linked_list_mutex);
if(it->first == -1) { int done = 0;
it->first = 1; int ret;
} else if(it->first) { lladd_linkedList_entry * entry;
lladd_linkedList_entry * entry = malloc(it->next.size); begin_action_ret(pthread_mutex_unlock, &linked_list_mutex, compensation_error()) {
Tread(xid, it->listRoot, entry); pthread_mutex_lock(&linked_list_mutex);
int listTouched;
listTouched = memcmp(&(entry->next), &(it->next), sizeof(recordid)); if(it->first == -1) {
free(entry); it->first = 1;
if(listTouched) { } else if(it->first) {
//The root entry was removed. Reset the iterator. entry = malloc(it->next.size);
it->first = -1; Tread(xid, it->listRoot, entry);
it->next = it->listRoot; int listTouched;
int ret = TlinkedListNext(xid, it, key, keySize, value, valueSize); listTouched = memcmp(&(entry->next), &(it->next), sizeof(recordid));
pthread_mutex_unlock(&linked_list_mutex); free(entry);
return ret; if(listTouched) {
} else { //The root entry was removed. Reset the iterator.
//continue as normal. it->first = -1;
it->first = 0; it->next = it->listRoot;
ret = TlinkedListNext(xid, it, key, keySize, value, valueSize);
// pthread_mutex_unlock(&linked_list_mutex);
done = 1;
// return ret;
} else {
//continue as normal.
it->first = 0;
}
} }
} end_action_ret(compensation_error());
if(done) {
pthread_mutex_unlock(&linked_list_mutex);
return ret;
} }
assert(it->keySize + it->valueSize + sizeof(lladd_linkedList_entry) == it->next.size); begin_action_ret(pthread_mutex_unlock, &linked_list_mutex, compensation_error()) {
assert(it->keySize + it->valueSize + sizeof(lladd_linkedList_entry) == it->next.size);
entry = malloc(it->next.size);
Tread(xid, it->next, entry);
} end_action_ret(compensation_error());
lladd_linkedList_entry * entry = malloc(it->next.size);
Tread(xid, it->next, entry);
int ret;
if(entry->next.size) { if(entry->next.size) {
*keySize = it->keySize; *keySize = it->keySize;
*valueSize = it->valueSize; *valueSize = it->valueSize;
@ -397,6 +451,7 @@ int TlinkedListNext(int xid, lladd_linkedList_iterator * it, byte ** key, int *
ret = 0; ret = 0;
} }
free(entry); free(entry);
pthread_mutex_unlock(&linked_list_mutex); pthread_mutex_unlock(&linked_list_mutex);
return ret; return ret;
} }