Implemented a linear hash from scratch. Concurrency hasn't been done, but it's probably correct in the single thread case.
This commit is contained in:
parent
5064e3fac2
commit
a078f25475
14 changed files with 674 additions and 10 deletions
|
@ -77,8 +77,8 @@ terms specified in this license.
|
|||
|
||||
/* #define MAX_BUFFER_SIZE 100003 */
|
||||
/*#define MAX_BUFFER_SIZE 10007*/
|
||||
/*#define MAX_BUFFER_SIZE 5003*/
|
||||
#define MAX_BUFFER_SIZE 2003
|
||||
#define MAX_BUFFER_SIZE 5003
|
||||
/*#define MAX_BUFFER_SIZE 2003 */
|
||||
/* #define MAX_BUFFER_SIZE 71 */
|
||||
/*#define MAX_BUFFER_SIZE 7 */
|
||||
/*#define BUFFER_ASOOCIATIVE 2 */
|
||||
|
|
17
lladd/crc32.h
Normal file
17
lladd/crc32.h
Normal file
|
@ -0,0 +1,17 @@
|
|||
/* This CRC code was taken from: http://www.axlradius.com/freestuff/crc2.c
|
||||
|
||||
(It is presumably in the public domain. Other files under /freestuff/ are...)
|
||||
|
||||
( Added a #include for this .h file. Otherwise, crc32 is a verbatim copy of the file from the internet.)
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Usage:
|
||||
unsigned long crc = -1L
|
||||
crc = crc32(buffer, length, crc)
|
||||
*/
|
||||
|
||||
unsigned long crc32(void *buffer, unsigned int count, unsigned long crc);
|
4
lladd/hash.h
Normal file
4
lladd/hash.h
Normal file
|
@ -0,0 +1,4 @@
|
|||
#include <lladd/crc32.h>
|
||||
|
||||
/** @todo replace() powl in hash with something more efficient, if hash() becomes a bottleneck. */
|
||||
unsigned int hash(void * val, long val_length, unsigned char tableBits, unsigned long nextExtension);
|
|
@ -148,7 +148,7 @@ typedef struct {
|
|||
#include "operations/noop.h"
|
||||
#include "operations/instantSet.h"
|
||||
#include "operations/arrayList.h"
|
||||
|
||||
#include "operations/linearHash.h"
|
||||
extern Operation operationsTable[]; /* [MAX_OPERATIONS]; memset somewhere */
|
||||
|
||||
/** Performs an operation during normal execution.
|
||||
|
|
26
lladd/operations/linearHash.h
Normal file
26
lladd/operations/linearHash.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
#include <lladd/operations.h>
|
||||
|
||||
#ifndef __LINEAR_HASH_H
|
||||
#define __LINEAR_HASH_H
|
||||
|
||||
/**
|
||||
@file
|
||||
|
||||
@ingroup OPERATIONS
|
||||
|
||||
$Id$
|
||||
*/
|
||||
|
||||
|
||||
|
||||
recordid ThashAlloc(int xid, int keySize, int valSize) ;
|
||||
|
||||
void ThashInsert(int xid, recordid hashRid,
|
||||
void * key, int keySize,
|
||||
void * val, int valSize);
|
||||
void ThashDelete(int xid, recordid hashRid,
|
||||
void * key, int keySize);
|
||||
void ThashUpdate(int xid, recordid hashRid, void * key, int keySize, void * val, int valSize);
|
||||
int ThashLookup(int xid, recordid hashRid, void * key, int keySize, void * buf, int valSize);
|
||||
|
||||
#endif
|
|
@ -3,13 +3,13 @@
|
|||
lib_LIBRARIES=liblladd.a
|
||||
#liblladd_a_LIBADD=logger/liblogger.a operations/liboperations.a
|
||||
# removed: recovery.c transactional.c logger.c logger/logparser.c logger/logstreamer.c
|
||||
liblladd_a_SOURCES=common.c stats.c io.c bufferManager.c linkedlist.c operations.c \
|
||||
liblladd_a_SOURCES=crc32.c common.c stats.c io.c bufferManager.c linkedlist.c operations.c \
|
||||
pageFile.c pageCache.c page.c blobManager.c recovery2.c transactional2.c \
|
||||
logger/logEntry.c logger/logWriter.c logger/logHandle.c logger/logger2.c \
|
||||
operations/pageOperations.c page/indirect.c operations/decrement.c \
|
||||
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
|
||||
operations/arrayList.c hash.c operations/linearHash.c
|
||||
AM_CFLAGS= -g -Wall -pedantic -std=gnu99
|
||||
|
||||
|
|
66
src/lladd/crc32.c
Normal file
66
src/lladd/crc32.c
Normal file
|
@ -0,0 +1,66 @@
|
|||
// Calculate a CRC 32 checksum.
|
||||
#include <lladd/crc32.h> /*Added 10-6-04 */
|
||||
#include <malloc.h>
|
||||
#include <stdio.h>
|
||||
|
||||
// LAST MODIFIED:[7-28-93]
|
||||
|
||||
// Usage:
|
||||
// unsigned long crc = -1L
|
||||
// crc = crc32(buffer, length, crc)
|
||||
|
||||
unsigned long crc32(void *buffer, unsigned int count, unsigned long crc);
|
||||
static int BuildCRCTable(void);
|
||||
|
||||
static unsigned long *CRCTable; // Table constructed for fast lookup.
|
||||
|
||||
#define CRC32_POLYNOMIAL 0xEDB88320L
|
||||
|
||||
// Initialize the CRC calculation table
|
||||
//
|
||||
static int BuildCRCTable(void)
|
||||
{
|
||||
int i, j;
|
||||
unsigned long crc;
|
||||
|
||||
CRCTable = malloc(256 * sizeof(unsigned long));
|
||||
if (CRCTable == NULL)
|
||||
{
|
||||
fprintf(stderr, "Can't malloc space for CRC table in file %s\n", __FILE__);
|
||||
return -1L;
|
||||
}
|
||||
|
||||
for (i = 0; i <= 255; i++)
|
||||
{
|
||||
crc = i;
|
||||
for (j = 8; j > 0; j--)
|
||||
if (crc & 1)
|
||||
crc = (crc >> 1) ^ CRC32_POLYNOMIAL;
|
||||
else
|
||||
crc >>= 1;
|
||||
CRCTable[i] = crc;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned long crc32(void *buffer, unsigned int count, unsigned long crc)
|
||||
{
|
||||
unsigned long temp1, temp2;
|
||||
static int firsttime = 1;
|
||||
unsigned char *p = (unsigned char *)buffer;
|
||||
|
||||
if (firsttime)
|
||||
{
|
||||
if (BuildCRCTable())
|
||||
return -1;
|
||||
firsttime = 0;
|
||||
}
|
||||
|
||||
while (count-- != 0)
|
||||
{
|
||||
temp1 = (crc >> 8) & 0x00FFFFFFL;
|
||||
temp2 = CRCTable[((int)crc ^ *p++) & 0xFF];
|
||||
crc = temp1 ^ temp2;
|
||||
}
|
||||
return crc;
|
||||
}
|
53
src/lladd/hash.c
Normal file
53
src/lladd/hash.c
Normal file
|
@ -0,0 +1,53 @@
|
|||
#include <lladd/hash.h>
|
||||
#include <math.h>
|
||||
/*static int thomasWangs32BitMixFunction(int key);
|
||||
static unsigned long thomasWangs64BitMixFunction(unsigned long key);*/
|
||||
|
||||
/** @todo replace powl in hash with something more efficient, if hash() becomes a bottleneck. */
|
||||
unsigned int hash(void * val, long val_length, unsigned char tableBits, unsigned long nextExtension) {
|
||||
unsigned long tableLength = powl(2, tableBits);
|
||||
unsigned long oldTableLength = powl(2, tableBits - 1);
|
||||
unsigned long unmixed = crc32(val, val_length, (unsigned long)-1L);
|
||||
|
||||
unsigned long ret = unmixed & (oldTableLength - 1);
|
||||
|
||||
if(*(int*)val == 4090) {
|
||||
printf("here too!");
|
||||
}
|
||||
|
||||
/* What would the low hash value be? */
|
||||
/* printf("hash(%d, bits=%d, ext=%ld) first: %ld ", *(int*)val, tableBits, nextExtension, ret); */
|
||||
if(ret < nextExtension) { /* Might be too low. */
|
||||
ret = unmixed & (tableLength - 1);
|
||||
/* printf("second: %ld", ret); */
|
||||
}
|
||||
/* printf("\n"); */
|
||||
|
||||
return (int) ret;
|
||||
}
|
||||
|
||||
/*static unsigned long thomasWangs64BitMixFunction(unsigned long key)
|
||||
{
|
||||
key += ~(key << 32L);
|
||||
key ^= (key >> 22L);
|
||||
key += ~(key << 13L);
|
||||
key ^= (key >> 8L);
|
||||
key += (key << 3L);
|
||||
key ^= (key >> 15L);
|
||||
key += ~(key << 27L);
|
||||
key ^= (key >> 31L);
|
||||
return key;
|
||||
}
|
||||
|
||||
static int thomasWangs32BitMixFunction(int key)
|
||||
{
|
||||
key += ~(key << 15);
|
||||
key ^= (key >> 10);
|
||||
key += (key << 3);
|
||||
key ^= (key >> 6);
|
||||
key += ~(key << 11);
|
||||
key ^= (key >> 16);
|
||||
return key;
|
||||
}
|
||||
|
||||
*/
|
|
@ -50,7 +50,7 @@ recordid TarrayListAlloc(int xid, int count, int multiplier, int size) {
|
|||
recordid rid;
|
||||
|
||||
rid.page = firstPage;
|
||||
rid.size = 0;
|
||||
rid.size = size;
|
||||
rid.slot = 0;
|
||||
|
||||
Tupdate(xid, rid, &tlp, OPERATION_ARRAY_LIST_ALLOC);
|
||||
|
|
281
src/lladd/operations/linearHash.c
Normal file
281
src/lladd/operations/linearHash.c
Normal file
|
@ -0,0 +1,281 @@
|
|||
#include <lladd/operations/linearHash.h>
|
||||
#include <lladd/hash.h>
|
||||
#include <limits.h>
|
||||
#include <assert.h>
|
||||
/**
|
||||
|
||||
A from-scratch implementation of linear hashing. Uses the
|
||||
arrayList operations to implement its hashbuckets.
|
||||
|
||||
*/
|
||||
|
||||
#define BUCKETS_OFFSET (2)
|
||||
|
||||
#define headerKeySize (headerRidA.page)
|
||||
#define headerValSize (headerRidA.slot)
|
||||
|
||||
#define headerHashBits (headerRidB.page)
|
||||
#define headerNextSplit (headerRidB.slot)
|
||||
|
||||
#include <math.h>
|
||||
#include <malloc.h>
|
||||
#include <string.h>
|
||||
#include <lladd/operations/linearHash.h>
|
||||
|
||||
|
||||
typedef struct {
|
||||
recordid next;
|
||||
} hashEntry;
|
||||
|
||||
void rehash(int xid, recordid hash, int next_split, int i);
|
||||
void update_hash_header(int xid, recordid hash, int i, int next_split);
|
||||
int deleteFromBucket(int xid, recordid hash, int bucket_number, void * key, int keySize, recordid * deletedEntry);
|
||||
void insertIntoBucket(int xid, recordid hashRid, int bucket_number, hashEntry * e, int keySize, int valSize, recordid deletedEntry);
|
||||
int findInBucket(int xid, recordid hashRid, int bucket_number, const void * key, int keySize, void * val, int valSize);
|
||||
|
||||
|
||||
int findInBucket(int xid, recordid hashRid, int bucket_number, const void * key, int keySize, void * val, int valSize) {
|
||||
hashEntry * e = malloc(sizeof(hashEntry) + keySize + valSize);
|
||||
|
||||
recordid bucket = hashRid;
|
||||
|
||||
bucket.slot = bucket_number;
|
||||
|
||||
recordid nextEntry;
|
||||
|
||||
Tread(xid, bucket, &nextEntry);
|
||||
if(nextEntry.size) {
|
||||
e = malloc(nextEntry.size);
|
||||
} else {
|
||||
e = malloc(1);
|
||||
}
|
||||
int found = 0;
|
||||
while(nextEntry.size > 0) {
|
||||
Tread(xid, nextEntry, e);
|
||||
if(!memcmp(key, e+1, keySize)) {
|
||||
memcpy(val, ((byte*)(e+1))+keySize, valSize);
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
nextEntry = e->next;
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
void expand (int xid, recordid hash, int next_split, int i) {
|
||||
TarrayListExtend(xid, hash, 1);
|
||||
if(next_split >= powl(2,i-1)+2) {
|
||||
/* printf("\n\n%d %d (i++)\n\n", next_split, i); */
|
||||
i++;
|
||||
next_split = 2;
|
||||
}
|
||||
/* printf("-%d-", next_split); */
|
||||
/* printf("rehash(%d, %d + 2)\n", i, next_split - 2); */
|
||||
rehash(xid, hash, next_split, i);
|
||||
next_split++;
|
||||
update_hash_header(xid, hash, i, next_split);
|
||||
}
|
||||
|
||||
void update_hash_header(int xid, recordid hash, int i, int next_split) {
|
||||
recordid headerRidB;
|
||||
|
||||
hash.slot = 1;
|
||||
Tread(xid, hash, &headerRidB);
|
||||
/* headerHashBits and headerHashSplit are #defined to refer to headerRidB. */
|
||||
headerHashBits = i;
|
||||
headerNextSplit = next_split;
|
||||
|
||||
Tset(xid, hash, &headerRidB);
|
||||
}
|
||||
|
||||
void rehash(int xid, recordid hashRid, int next_split, int i) {
|
||||
recordid bucket = hashRid;
|
||||
bucket.slot = next_split;
|
||||
recordid headerRidA;
|
||||
Tread(xid, hashRid, &headerRidA);
|
||||
/* recordid oldRid;
|
||||
oldRid.page = 0;
|
||||
oldRid.slot = 0;
|
||||
oldRid.size = 0; */
|
||||
hashEntry * e = calloc(1,sizeof(hashEntry) + headerValSize + headerKeySize);
|
||||
assert(bucket.size < 1000);
|
||||
|
||||
if(bucket.size) {
|
||||
Tread(xid, bucket, &bucket);
|
||||
}
|
||||
|
||||
while(bucket.size > 0) {
|
||||
Tread(xid, bucket, e);
|
||||
|
||||
/* printf("#%d", *(int*)(e+1)); */
|
||||
|
||||
int old_hash = hash(e+1, headerKeySize, i-1, ULONG_MAX) + 2;
|
||||
assert(next_split == old_hash);
|
||||
|
||||
int new_hash = hash(e+1, headerKeySize, i, ULONG_MAX) + 2;
|
||||
|
||||
bucket = e->next;
|
||||
/* oldRid = bucket; */
|
||||
assert((!bucket.size )|| bucket.size == sizeof(hashEntry) + headerValSize + headerKeySize);
|
||||
|
||||
if(new_hash != next_split) {
|
||||
|
||||
assert(new_hash == next_split + powl(2, i-1));
|
||||
|
||||
/* recordid newRid = hashRid;
|
||||
newRid.slot = new_hash;
|
||||
recordid ptr;
|
||||
Tread(xid, newRid, &ptr); */
|
||||
/* printf("Moving from %d to %d.\n", next_split, new_hash);
|
||||
fflush(NULL); */
|
||||
recordid oldEntry;
|
||||
|
||||
/* printf("!"); */
|
||||
|
||||
assert(deleteFromBucket(xid, hashRid, next_split, e+1, headerKeySize, &oldEntry));
|
||||
insertIntoBucket(xid, hashRid, new_hash, e, headerKeySize, headerValSize, oldEntry);
|
||||
} else {
|
||||
|
||||
/* printf("-"); */
|
||||
|
||||
/* printf("Not moving %d.\n", next_split);
|
||||
fflush(NULL); */
|
||||
}
|
||||
|
||||
}
|
||||
free(e);
|
||||
}
|
||||
|
||||
void insertIntoBucket(int xid, recordid hashRid, int bucket_number, hashEntry * e, int keySize, int valSize, recordid newEntry) {
|
||||
recordid deleteMe;
|
||||
if(deleteFromBucket(xid, hashRid, bucket_number, e+1, keySize, &deleteMe)) {
|
||||
Tdealloc(xid, deleteMe);
|
||||
}
|
||||
|
||||
/*@todo consider recovery for insertIntoBucket. */
|
||||
/* recordid newEntry = Talloc(xid, sizeof(hashEntry) + keySize + valSize); */
|
||||
recordid bucket = hashRid;
|
||||
bucket.slot = bucket_number;
|
||||
Tread(xid, bucket, &(e->next));
|
||||
Tset(xid, newEntry, e);
|
||||
Tset(xid, bucket, &newEntry);
|
||||
}
|
||||
|
||||
int deleteFromBucket(int xid, recordid hash, int bucket_number, void * key, int keySize, recordid * deletedEntry) {
|
||||
hashEntry * e;
|
||||
recordid bucket = hash;
|
||||
bucket.slot = bucket_number;
|
||||
recordid nextEntry;
|
||||
Tread(xid, bucket, &nextEntry);
|
||||
if(nextEntry.size) {
|
||||
e = calloc(1,nextEntry.size);
|
||||
} else {
|
||||
e = calloc(1,1);
|
||||
}
|
||||
int first = 1;
|
||||
int found = 0;
|
||||
recordid lastEntry;
|
||||
while(nextEntry.size > 0) {
|
||||
Tread(xid, nextEntry, e);
|
||||
if(!memcmp(key, e+1, keySize)) {
|
||||
if(first) {
|
||||
assert(e->next.size < 1000);
|
||||
Tset(xid, bucket, &(e->next));
|
||||
} else {
|
||||
recordid next = e->next;
|
||||
Tread(xid, lastEntry, e);
|
||||
assert(next.size < 1000);
|
||||
e->next = next;
|
||||
Tset(xid, lastEntry, e);
|
||||
}
|
||||
*deletedEntry = nextEntry;
|
||||
/* Tdealloc(xid, nextEntry); */
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
lastEntry = nextEntry;
|
||||
first = 0;
|
||||
nextEntry = e->next;
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
recordid ThashAlloc(int xid, int keySize, int valSize) {
|
||||
/* Want 16 buckets + 2 header rids, doubling on overflow. */
|
||||
recordid rid = TarrayListAlloc(xid, 16 + 2, 2, sizeof(recordid));
|
||||
TarrayListExtend(xid, rid, 32+2);
|
||||
|
||||
recordid headerRidA, headerRidB;
|
||||
|
||||
headerKeySize = keySize;
|
||||
headerValSize = valSize;
|
||||
|
||||
headerNextSplit = INT_MAX;
|
||||
headerHashBits = 4;
|
||||
|
||||
rid.slot =0;
|
||||
Tset(xid, rid, &headerRidA);
|
||||
rid.slot =1;
|
||||
Tset(xid, rid, &headerRidB);
|
||||
rid.slot =0;
|
||||
return rid;
|
||||
}
|
||||
|
||||
void ThashInsert(int xid, recordid hashRid,
|
||||
void * key, int keySize,
|
||||
void * val, int valSize) {
|
||||
|
||||
recordid headerRidA, headerRidB;
|
||||
recordid tmp = hashRid;
|
||||
tmp.slot = 0;
|
||||
Tread(xid, tmp, &headerRidA);
|
||||
assert(headerKeySize == keySize);
|
||||
tmp.slot = 1;
|
||||
Tread(xid, tmp, &headerRidB);
|
||||
assert(headerValSize == valSize);
|
||||
|
||||
int bucket = hash(key, keySize, headerHashBits, headerNextSplit - 2) + 2;
|
||||
|
||||
hashEntry * e = calloc(1,sizeof(hashEntry) + keySize + valSize);
|
||||
memcpy(e+1, key, keySize);
|
||||
memcpy(((byte*)(e+1)) + keySize, val, valSize);
|
||||
|
||||
recordid newEntry = Talloc(xid, sizeof(hashEntry) + keySize + valSize);
|
||||
/* printf("%d -> %d\n", *(int*)(e+1), bucket); */
|
||||
insertIntoBucket(xid, hashRid, bucket, e, keySize, valSize, newEntry);
|
||||
expand(xid, hashRid, headerNextSplit, headerHashBits);
|
||||
|
||||
free(e);
|
||||
|
||||
}
|
||||
/** @todo hash hable probably should track the number of items in it,
|
||||
so that expand can be selectively called. */
|
||||
void ThashDelete(int xid, recordid hashRid,
|
||||
void * key, int keySize) {
|
||||
|
||||
recordid headerRidB;
|
||||
recordid tmp = hashRid;
|
||||
tmp.slot = 1;
|
||||
Tread(xid, tmp, &headerRidB);
|
||||
int bucket_number = hash(key, keySize, headerHashBits, headerNextSplit - 2) + 2;
|
||||
recordid deleteMe;
|
||||
if(deleteFromBucket(xid, hashRid, bucket_number, key, keySize, &deleteMe)) {
|
||||
Tdealloc(xid, deleteMe);
|
||||
}
|
||||
}
|
||||
|
||||
void ThashUpdate(int xid, recordid hashRid, void * key, int keySize, void * val, int valSize) {
|
||||
ThashDelete(xid, hashRid, key, keySize);
|
||||
ThashInsert(xid, hashRid, key, keySize, val, valSize);
|
||||
}
|
||||
|
||||
int ThashLookup(int xid, recordid hashRid, void * key, int keySize, void * buf, int valSize) {
|
||||
recordid headerRidB;
|
||||
recordid tmp = hashRid;
|
||||
tmp.slot = 1;
|
||||
Tread(xid, tmp, &headerRidB);
|
||||
int bucket_number = hash(key, keySize, headerHashBits, headerNextSplit - 2) + 2;
|
||||
/* printf("look in %d\n", bucket_number); */
|
||||
int ret = findInBucket(xid, hashRid, bucket_number, key, keySize, buf, valSize);
|
||||
return ret;
|
||||
}
|
|
@ -148,7 +148,7 @@ void pageOperationsInit() {
|
|||
|
||||
assert(freepage);
|
||||
|
||||
free(p.memAddr);
|
||||
/* free(p.memAddr); */
|
||||
|
||||
deletelock(p.loadlatch);
|
||||
deletelock(p.rwlatch);
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
AM_CFLAGS= -g -Wall -pedantic -std=gnu99
|
||||
|
||||
|
|
217
test/lladd/check_linearHash.c
Normal file
217
test/lladd/check_linearHash.c
Normal file
|
@ -0,0 +1,217 @@
|
|||
/*---
|
||||
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 <config.h>
|
||||
#include <check.h>
|
||||
#include "../check_includes.h"
|
||||
|
||||
#include <lladd/transactional.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <lladd/hash.h>
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
|
||||
#define LOG_NAME "check_linearHash.log"
|
||||
|
||||
/** @test
|
||||
executes each of the insert / remove / lookup operations a few times.
|
||||
*/
|
||||
#define NUM_ENTRIES 100000
|
||||
/* #define NUM_ENTRIES 2000*/
|
||||
/* #define NUM_ENTRIES 1000 */
|
||||
/*#define NUM_ENTRIES 100 */
|
||||
|
||||
START_TEST(checkHashFcn) {
|
||||
int i;
|
||||
srandom(12312313);
|
||||
for(i = 0; i < 100000;i++) {
|
||||
int j = (int) (100000.0*random()/(RAND_MAX+1.0)); /* int for CRC. */
|
||||
int k = (int) 2+(30.0*random()/(RAND_MAX+1.0)); /* number of bits in result. */
|
||||
|
||||
unsigned long first = hash(&j, sizeof(int), k, ULONG_MAX);
|
||||
int boundary = first + 10;
|
||||
unsigned long second = hash(&j, sizeof(int), k, boundary);
|
||||
assert(first == second);
|
||||
unsigned long third = hash(&j, sizeof(int), k+1, ULONG_MAX);
|
||||
assert((first == third) || (powl(2,k)+ first == third));
|
||||
}
|
||||
} END_TEST
|
||||
|
||||
START_TEST(simpleLinearHashTest)
|
||||
{
|
||||
Tinit();
|
||||
|
||||
int xid = Tbegin();
|
||||
|
||||
recordid hashRoot = ThashAlloc(xid, sizeof(int), sizeof(recordid));
|
||||
|
||||
for(int i = 0; i < NUM_ENTRIES; i++) {
|
||||
recordid rid;
|
||||
rid.page=i+1;
|
||||
rid.slot=i+2;
|
||||
rid.size=i+3;
|
||||
|
||||
/* assert(isNullRecord(lHtInsert(xid, hash, &i, sizeof(int), rid)));
|
||||
assert(!isNullRecord(lHtInsert(xid, hash, &i, sizeof(int), rid))); */
|
||||
if(i == 4090) {
|
||||
printf("here");
|
||||
}
|
||||
ThashInsert(xid, hashRoot, &i, sizeof(int), &rid, sizeof(recordid));
|
||||
/* printf("%d\n", i); */
|
||||
assert(ThashLookup(xid, hashRoot, &i, sizeof(int), &rid, sizeof(recordid)));
|
||||
|
||||
assert(rid.page == i+1);
|
||||
assert(rid.slot == i+2);
|
||||
assert(rid.size == i+3);
|
||||
|
||||
|
||||
if(! (i % 1000)) {
|
||||
printf("%d\n", i);
|
||||
fflush(NULL);
|
||||
}
|
||||
|
||||
}
|
||||
printf("Done inserting.\n");
|
||||
fflush(NULL);
|
||||
|
||||
for(int i = 0; i < NUM_ENTRIES; i+=10) {
|
||||
/*recordid rid = lHtRemove(xid, hash, &i, sizeof(int)); */
|
||||
recordid rid;
|
||||
assert(ThashLookup(xid, hashRoot, &i, sizeof(int), &rid, sizeof(recordid)));
|
||||
assert(rid.page == (i+1));
|
||||
assert(rid.slot == (i+2));
|
||||
assert(rid.size == (i+3));
|
||||
ThashDelete(xid, hashRoot, &i, sizeof(int));
|
||||
|
||||
}
|
||||
|
||||
printf("Done deleting mod 10.\n");
|
||||
fflush(NULL);
|
||||
|
||||
|
||||
for(int i = 0; i < NUM_ENTRIES; i++) {
|
||||
recordid rid;
|
||||
if(i % 10) {
|
||||
assert(ThashLookup(xid, hashRoot, &i, sizeof(int), &rid, sizeof(recordid)));
|
||||
assert(rid.page == (i+1));
|
||||
assert(rid.slot == (i+2));
|
||||
assert(rid.size == (i+3));
|
||||
} else {
|
||||
assert(!ThashLookup(xid, hashRoot, &i, sizeof(int), &rid, sizeof(recordid)));
|
||||
}
|
||||
}
|
||||
|
||||
printf("Done checking mod 10.\n");
|
||||
|
||||
Tcommit(xid);
|
||||
xid = Tbegin();
|
||||
recordid rid;
|
||||
for(int i = 0; i < NUM_ENTRIES; i++) {
|
||||
|
||||
if(i % 10) {
|
||||
assert(ThashLookup(xid, hashRoot, &i, sizeof(int), &rid, sizeof(recordid)));
|
||||
ThashDelete(xid, hashRoot, &i, sizeof(int));
|
||||
assert(rid.page == (i+1));
|
||||
assert(rid.slot == (i+2));
|
||||
assert(rid.size == (i+3));
|
||||
} else {
|
||||
assert(!ThashLookup(xid, hashRoot, &i, sizeof(int), &rid, sizeof(recordid)));
|
||||
ThashDelete(xid, hashRoot, &i, sizeof(int));
|
||||
}
|
||||
}
|
||||
|
||||
printf("Done deleting rest.\n");
|
||||
fflush(NULL);
|
||||
|
||||
for(int i = 0; i < NUM_ENTRIES; i++) {
|
||||
assert(!ThashLookup(xid, hashRoot, &i, sizeof(int), &rid, sizeof(recordid)));
|
||||
}
|
||||
|
||||
printf("Aborting..\n");
|
||||
fflush(NULL);
|
||||
Tabort(xid);
|
||||
printf("done aborting..\n");
|
||||
fflush(NULL);
|
||||
|
||||
xid = Tbegin();
|
||||
|
||||
for(int i = 0; i < NUM_ENTRIES; i++) {
|
||||
if(i % 10) {
|
||||
assert( ThashLookup(xid, hashRoot, &i, sizeof(int), &rid, sizeof(recordid)));
|
||||
assert(rid.page == (i+1));
|
||||
assert(rid.slot == (i+2));
|
||||
assert(rid.size == (i+3));
|
||||
} else {
|
||||
assert(!ThashLookup(xid, hashRoot, &i, sizeof(int), &rid, sizeof(recordid)));
|
||||
}
|
||||
}
|
||||
printf("done checking..\n");
|
||||
fflush(NULL);
|
||||
|
||||
Tcommit(xid);
|
||||
|
||||
Tdeinit();
|
||||
|
||||
}
|
||||
END_TEST
|
||||
|
||||
Suite * check_suite(void) {
|
||||
Suite *s = suite_create("linearHash");
|
||||
/* Begin a new test */
|
||||
TCase *tc = tcase_create("simple");
|
||||
|
||||
|
||||
/* Sub tests are added, one per line, here */
|
||||
|
||||
/* tcase_add_test(tc, checkHashFcn); */
|
||||
tcase_add_test(tc, simpleLinearHashTest);
|
||||
|
||||
/* --------------------------------------------- */
|
||||
|
||||
tcase_add_checked_fixture(tc, setup, teardown);
|
||||
|
||||
suite_add_tcase(s, tc);
|
||||
return s;
|
||||
}
|
||||
|
||||
#include "../check_setup.h"
|
|
@ -63,7 +63,7 @@ int main() {
|
|||
printf("Couldn't open log.\n");
|
||||
}
|
||||
|
||||
lh = getLSNHandle(44);
|
||||
lh = getLogHandle(); /*LSNHandle(0); */
|
||||
|
||||
while((le = nextInLog(&lh))) {
|
||||
|
||||
|
|
Loading…
Reference in a new issue