Commit 32321fb2 authored by Lubos Slovak's avatar Lubos Slovak

Code refactoring.

Function main() moved to new file main.c.
Bitset test moved to new files test.[ch].
Tests related to cuckoo table remain in cuckoo-test.[ch].
Removed rwlocks from ck_hash_table (will be replaced by standalone
  item lock implementation).
parent a448fb8e
......@@ -96,18 +96,6 @@ static inline uint8_t NEXT_GENERATION( uint8_t flags ) {
return (flags ^ FLAG_GENERATION_BOTH);
}
//static int REHASH_IN_PROGRESS( uint8_t flags ) {
// return ((flags & FLAG_REHASH) != 0);
//}
//
//static void SET_REHASH( uint8_t *flags ) {
// (*flags) |= FLAG_REHASH;
//}
//
//static void UNSET_REHASH( uint8_t *flags ) {
// (*flags) &= ~FLAG_REHASH;
//}
/*----------------------------------------------------------------------------*/
#define CK_SIZE_NEAREST 1
......@@ -259,6 +247,17 @@ int ck_insert_to_buffer( ck_hash_table *table, ck_hash_table_item *item )
/*----------------------------------------------------------------------------*/
static inline uint ck_items_match( const ck_hash_table_item* item,
const char *key, size_t length,
uint generation )
{
return (length == item->key_length
&& (strncmp(item->key, key, length) == 0)
/*&& (GET_GENERATION(item->timestamp) == generation)*/) ? 0 : -1;
}
/*----------------------------------------------------------------------------*/
ck_hash_table_item *ck_find_in_buffer( ck_hash_table *table, const char *key,
uint length, uint generation )
{
......@@ -267,8 +266,7 @@ ck_hash_table_item *ck_find_in_buffer( ck_hash_table *table, const char *key,
#endif
uint i = 0;
while (i < table->buf_i
&& ((strncmp(table->buffer[i].key, key, length) != 0)
|| GET_GENERATION(table->buffer[i].timestamp) != generation))
&& ck_items_match(&table->buffer[i], key, length, generation))
{
++i;
}
......@@ -278,7 +276,7 @@ ck_hash_table_item *ck_find_in_buffer( ck_hash_table *table, const char *key,
}
assert(strncmp(table->buffer[i].key, key, length) == 0);
assert(GET_GENERATION(table->buffer[i].timestamp) == generation);
//assert(GET_GENERATION(table->buffer[i].timestamp) == generation);
return &table->buffer[i];
}
......@@ -353,10 +351,6 @@ ck_hash_table *ck_create_table( uint items, void (*dtor_item)( void *value ) )
// initialize rehash mutex
pthread_mutex_init(&table->mtx_table, NULL);
// initialize rwlocks for items
pthread_rwlock_init(&table->rwlock_item1, NULL);
pthread_rwlock_init(&table->rwlock_item2, NULL);
// set the generation to 1 and initialize the universal system
CLEAR_FLAGS(&table->generation);
SET_GENERATION1(&table->generation);
......@@ -434,13 +428,6 @@ void ck_destroy_table( ck_hash_table **table )
// destroy mutex, assuming that here noone will lock the mutex again
pthread_mutex_destroy(&(*table)->mtx_table);
// wait for other threads to unlock the rwlocks
while (pthread_rwlock_trywrlock(&(*table)->rwlock_item1) != 0
|| pthread_rwlock_trywrlock(&(*table)->rwlock_item2) != 0 ) {}
// destroy rwlocks, assuming that here noone will lock them again
pthread_rwlock_destroy(&(*table)->rwlock_item1);
pthread_rwlock_destroy(&(*table)->rwlock_item2);
free((*table)->table1);
(*table)->table1 = NULL;
free((*table)->table2);
......@@ -624,30 +611,28 @@ int ck_hash_item( ck_hash_table *table, ck_hash_table_item *old,
next_table = TABLE_1;
}
switch (next_table) {
case TABLE_1:
hash = HASH1(next->key, next->key_length, table->table_size_exp,
NEXT_GENERATION(table->generation));
next = &table->table1[hash];
// check if this cell wasn't already used in this item's hashing
if (ck_check_used2(used1, used_i1, hash) != 0) {
next = free;
goto moving;
}
if (next_table == TABLE_1) {
hash = HASH1(next->key, next->key_length, table->table_size_exp,
NEXT_GENERATION(table->generation));
next = &table->table1[hash];
// check if this cell wasn't already used in this item's hashing
if (ck_check_used2(used1, used_i1, hash) != 0) {
next = free;
break;
case TABLE_2:
hash = HASH2(next->key, next->key_length, table->table_size_exp,
NEXT_GENERATION(table->generation));
next = &table->table2[hash];
// check if this cell wasn't already used in this item's hashing
if (ck_check_used2(used2, used_i2, hash) != 0) {
next = free;
goto moving;
}
}
} else if (next_table == TABLE_2) {
hash = HASH2(next->key, next->key_length, table->table_size_exp,
NEXT_GENERATION(table->generation));
next = &table->table2[hash];
// check if this cell wasn't already used in this item's hashing
if (ck_check_used2(used2, used_i2, hash) != 0) {
next = free;
break;
default:
assert(0);
}
} else {
assert(0);
}
NEXT_TABLE(next_table);
......@@ -655,8 +640,6 @@ int ck_hash_item( ck_hash_table *table, ck_hash_table_item *old,
assert(next->value == 0);
moving:
ck_copy_item_contents(moving, next);
// set the new generation for the inserted item
SET_NEXT_GENERATION(&next->timestamp);
......@@ -676,14 +659,14 @@ static inline void ck_set_generation_to_items( ck_hash_table_item *items,
SET_GENERATION(&items[indexes[i]].timestamp, generation);
}
}
/*----------------------------------------------------------------------------*/
int ck_rehash( ck_hash_table *table )
{
pthread_mutex_lock(&table->mtx_table);
fprintf(stderr, "Rehashing not implemented yet!");
return -1;
//fprintf(stderr, "Rehashing not implemented yet!");
pthread_mutex_lock(&table->mtx_table);
// we already have functions for the next generation, begin rehashing
// we wil use the last item in the buffer as the old cell
......@@ -700,6 +683,7 @@ int ck_rehash( ck_hash_table *table )
continue;
}
// otherwise copy the item for rehashing
ck_copy_item_contents(&table->table1[rehashed], old);
// clear the place so that this item will not get rehashed again
ck_clear_item(&table->table1[rehashed]);
......@@ -723,26 +707,6 @@ int ck_rehash( ck_hash_table *table )
pthread_mutex_unlock(&table->mtx_table);
return 0;
// // TODO: synchronization!
// // get new function for the next generation
// if (us_next(SWAP_GENERATIONS(&table->generation)) != 0) {
// return -2; // rehashed, but no new functions
// }
//
// return 0;
}
/*----------------------------------------------------------------------------*/
static inline uint ck_items_match( const ck_hash_table_item* item,
const char *key, size_t length,
uint generation )
{
return (length == item->key_length
&& (strncmp(item->key, key, length) == 0)
/*&& (GET_GENERATION(item->timestamp) == generation)*/) ? 0 : -1;
}
/*----------------------------------------------------------------------------*/
......
......@@ -32,11 +32,6 @@ typedef struct {
void (*dtor_item)( void *value );
pthread_mutex_t mtx_table;
unsigned long item1;
unsigned long item2;
pthread_rwlock_t rwlock_item1;
pthread_rwlock_t rwlock_item2;
} ck_hash_table;
/*----------------------------------------------------------------------------*/
......
/**
* @todo Do not hash the string with the ending '\0'.
*/
#include "cuckoo-test.h"
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include "common.h"
#include "cuckoo-hash-table.h"
#include "dns-simple.h"
#include "bitset.h"
#include "socket-manager.h"
//#define TEST_DEBUG
//#define TEST_LOOKUP
//#define TEST_OUTPUT
//#define CK_TEST_DEBUG
//#define CK_TEST_LOOKUP
//#define CK_TEST_OUTPUT
#ifdef CK_TEST_DEBUG
#define CK_TEST_LOOKUP
#define CK_TEST_OUTPUT
#endif
static const uint ERR_ARG = 1;
static const uint ERR_FILE_OPEN = 2;
static const uint ERR_FILE_READ = 3;
static const uint ERR_TABLE_CREATE = 4;
static const uint ERR_INSERT = 5;
static const uint ERR_LOOKUP = 6;
static const uint ERR_ALLOC_ITEMS = 7;
static const uint ERR_FIND = 8;
#define ERR_COUNT 1
#define ERR_FILE_OPEN 2
#define ERR_FILE_READ 3
#define ERR_TABLE_CREATE 4
#define ERR_INSERT 5
#define ERR_LOOKUP 6
#define ERR_ALLOC_ITEMS 7
#define ERR_FIND 8
#define ERR_FILL 9
static const uint BUF_SIZE = 20;
static const uint ARRAY_SIZE = 500;
......@@ -33,13 +36,13 @@ static const uint THREAD_COUNT = 2;
/*----------------------------------------------------------------------------*/
// macro for hash table types
#define CK_KEY_TYPE (char *)
#define CK_VALUE_TYPE (char *)
//#define CK_KEY_TYPE (char *)
//#define CK_VALUE_TYPE (char *)
/*----------------------------------------------------------------------------*/
// global var for counting collisions
unsigned long collisions = 0;
static unsigned long collisions = 0;
// static global var for the hash table (change later!)
static ck_hash_table *table;
......@@ -97,7 +100,7 @@ int hash_from_file( FILE *file, ck_hash_table *table, uint items,
while (ch != EOF) {
buf_i = 0;
#ifdef TEST_DEBUG
#ifdef CK_TEST_DEBUG
printf("Allocating buffer\n");
#endif
// allocate some buffer
......@@ -108,13 +111,13 @@ int hash_from_file( FILE *file, ck_hash_table *table, uint items,
fprintf(stderr, "Allocation failed.\n");
return -1;
}
#ifdef TEST_DEBUG
#ifdef CK_TEST_DEBUG
printf("Done\n");
#endif
ch = fgetc(file);
while (ch != ' ' && ch != '\n' && ch != EOF) {
//#ifdef TEST_DEBUG
//#ifdef CK_TEST_DEBUG
// printf("Read character: %c\n", ch);
//#endif
......@@ -141,7 +144,7 @@ int hash_from_file( FILE *file, ck_hash_table *table, uint items,
ch = fgetc(file);
}
#ifdef TEST_DEBUG
#ifdef CK_TEST_DEBUG
printf("Read domain name: %s\n", buffer);
#endif
// if buffer too large
......@@ -152,7 +155,7 @@ int hash_from_file( FILE *file, ck_hash_table *table, uint items,
free(buffer);
return -1;
}
#ifdef TEST_DEBUG
#ifdef CK_TEST_DEBUG
printf("Read domain name %s, inserting...\n", buffer);
#endif
if (buf_i > 0) {
......@@ -167,7 +170,7 @@ int hash_from_file( FILE *file, ck_hash_table *table, uint items,
return ERR_INSERT;
}
#ifdef TEST_DEBUG
#ifdef CK_TEST_DEBUG
printf("Creating RR with the given owner name.\n");
#endif
value = dnss_create_rr(buffer);
......@@ -191,7 +194,7 @@ int hash_from_file( FILE *file, ck_hash_table *table, uint items,
return ERR_INSERT;
}
#ifdef TEST_DEBUG
#ifdef CK_TEST_DEBUG
if (line % 100000 == 1) {
fprintf(stderr, "Inserting item number %u, key: %s..\n",
line, key);
......@@ -209,7 +212,7 @@ int hash_from_file( FILE *file, ck_hash_table *table, uint items,
return ERR_INSERT;
}
#ifdef TEST_DEBUG
#ifdef CK_TEST_DEBUG
if (line % 100000 == 0) {
fprintf(stderr, "Done, %lu collisions so far.\n", collisions);
}
......@@ -259,7 +262,7 @@ int test_lookup_from_file( ck_hash_table *table, FILE *file )
while (ch != EOF) {
buf_i = 0;
#ifdef TEST_DEBUG
#ifdef CK_TEST_DEBUG
printf("Allocating buffer\n");
#endif
......@@ -271,13 +274,13 @@ int test_lookup_from_file( ck_hash_table *table, FILE *file )
fprintf(stderr, "Allocation failed.\n");
return -1;
}
#ifdef TEST_DEBUG
#ifdef CK_TEST_DEBUG
printf("Done\n");
#endif
ch = fgetc(file);
while ((ch != ' ' && ch != '\n') && ch != EOF) {
#ifdef TEST_DEBUG
#ifdef CK_TEST_DEBUG
printf("Read character: %c\n", ch);
#endif
......@@ -303,7 +306,7 @@ int test_lookup_from_file( ck_hash_table *table, FILE *file )
ch = fgetc(file);
}
#ifdef TEST_DEBUG
#ifdef CK_TEST_DEBUG
printf("Read domain name: %s\n", buffer);
#endif
......@@ -316,7 +319,9 @@ int test_lookup_from_file( ck_hash_table *table, FILE *file )
return -1;
}
//printf("Read domain name %s, inserting...\n", buffer);
#ifdef CK_TEST_DEBUG
printf("Read domain name %s, searching...\n", buffer);
#endif
if (buf_i > 0) {
// find domain name
......@@ -329,9 +334,13 @@ int test_lookup_from_file( ck_hash_table *table, FILE *file )
return -1;
}
#ifdef CK_TEST_DEBUG
printf("Wire format of the domain name:\n");
hex_print(key, key_size);
#endif
if ((res = ck_find_item(table, key,
dnss_wire_dname_size(buffer) - 1)) == NULL
key_size - 1)) == NULL
|| strncmp(res->key, key, dnss_wire_dname_size(buffer) - 1) != 0 ) {
fprintf(stderr, "\nItem with key %s not found.\n", buffer);
free(key);
......@@ -339,7 +348,7 @@ int test_lookup_from_file( ck_hash_table *table, FILE *file )
return ERR_FIND;
}
#if defined TEST_DEBUG || defined TEST_LOOKUP
#ifdef CK_TEST_LOOKUP
else {
printf("Table 1, key: %s, rdata: %*s, key length: %lu\n",
res->key, ((dnss_rr *)(res->value))->rdlength,
......@@ -358,98 +367,6 @@ int test_lookup_from_file( ck_hash_table *table, FILE *file )
/*----------------------------------------------------------------------------*/
int test_bitset()
{
bitset_t bitset;
uint n = 1048576, i, c, err = 0;
uint *numbers = malloc(n/2 * sizeof(uint));
BITSET_CREATE(&bitset, n);
BITSET_CLEAR(bitset, n);
printf("New bitset created.\n");
// check if empty
for (i = 0; i < n; i++) {
if (BITSET_GET(bitset, i) != 0) {
printf("Bit %u not clear!\n", i);
err++;
}
}
srand(1);
printf("Setting random bits...\n");
// set random bits, but keep track of them
for (i = 0; i < n/2; i++) {
c = rand() % n;
//printf("Setting bit on position %u..\n", c);
numbers[i] = c;
BITSET_SET(bitset, c);
if (!BITSET_ISSET(bitset, c)) {
printf("Bit %u not set successfully!\n", c);
err++;
}
BITSET_UNSET(bitset, c);
}
printf("Testing borders...\n");
// setting bits on the borders
BITSET_SET(bitset, 0);
if (!BITSET_ISSET(bitset, 0)) {
printf("Error setting bit on position 0.\n");
err++;
}
BITSET_UNSET(bitset, 0);
BITSET_SET(bitset, 31);
if (!BITSET_ISSET(bitset, 31)) {
printf("Error setting bit on position 31.\n");
err++;
}
BITSET_UNSET(bitset, 31);
BITSET_SET(bitset, 32);
if (!BITSET_ISSET(bitset, 32)) {
printf("Error setting bit on position 32.\n");
err++;
}
BITSET_UNSET(bitset, 32);
BITSET_SET(bitset, 33);
if (!BITSET_ISSET(bitset, 33)) {
printf("Error setting bit on position 33.\n");
err++;
}
BITSET_UNSET(bitset, 33);
BITSET_SET(bitset, 1048575);
if (!BITSET_ISSET(bitset, 1048575)) {
printf("Error setting bit on position 1048575.\n");
err++;
}
BITSET_UNSET(bitset, 1048575);
// check if empty
for (i = 0; i < n; i++) {
if (BITSET_GET(bitset, i) != 0) {
printf("Bit %u not clear!\n", i);
err++;
}
}
free(numbers);
BITSET_DESTROY(&bitset);
printf("There were %u errors.\n", err);
return 0;
}
/*----------------------------------------------------------------------------*/
void destroy_items( void *item )
{
dnss_rr *rr = (dnss_rr *)item;
......@@ -462,7 +379,7 @@ void answer_request( const char *query_wire, uint size,
char *response_wire, uint *response_size )
// in *response_size we have the maximum acceptable size of the response
{
#if defined(TEST_DEBUG) || defined(TEST_OUTPUT)
#ifdef CK_TEST_OUTPUT
printf("answer_request() called with query size %d.\n", size);
hex_print(query_wire, size);
#endif
......@@ -472,7 +389,7 @@ void answer_request( const char *query_wire, uint size,
return;
}
#if defined(TEST_DEBUG) || defined(TEST_OUTPUT)
#ifdef CK_TEST_OUTPUT
printf("Query parsed, ID: %u, QNAME: %s\n", query->header.id,
query->questions[0].qname);
hex_print(query->questions[0].qname, strlen(query->questions[0].qname));
......@@ -489,7 +406,7 @@ void answer_request( const char *query_wire, uint size,
}
if (item == NULL) {
#if defined(TEST_DEBUG) || defined(TEST_OUTPUT)
#ifdef CK_TEST_OUTPUT
printf("Requested name not found, returning empty response.\n");
#endif
if (dnss_create_response(query, NULL, 0, &response) != 0) {
......@@ -498,7 +415,7 @@ void answer_request( const char *query_wire, uint size,
return;
}
} else {
#if defined(TEST_DEBUG) || defined(TEST_OUTPUT)
#ifdef CK_TEST_OUTPUT
printf("Requested name found.\n");
#endif
if (dnss_create_response(query, (dnss_rr *)item->value,
......@@ -509,12 +426,12 @@ void answer_request( const char *query_wire, uint size,
}
}
#if defined(TEST_DEBUG) || defined(TEST_OUTPUT)
#ifdef CK_TEST_OUTPUT
printf("Response ID: %u\n", response->header.id);
#endif
if (dnss_wire_format(response, response_wire, response_size) != 0) {
#if defined(TEST_DEBUG) || defined(TEST_OUTPUT)
#ifdef CK_TEST_OUTPUT
fprintf(stderr, "Response too long, returning SERVFAIL response.\n");
#endif
if (dnss_create_error_response(query, &response) != 0) {
......@@ -526,7 +443,7 @@ void answer_request( const char *query_wire, uint size,
assert(res != 0);
}
#if defined(TEST_DEBUG) || defined(TEST_OUTPUT)
#ifdef CK_TEST_OUTPUT
printf("Returning response of size: %u.\n", *response_size);
#endif
......@@ -536,73 +453,155 @@ void answer_request( const char *query_wire, uint size,
/*----------------------------------------------------------------------------*/
int main( int argc, char **argv )
int count_domain_names( FILE *file, uint *names, unsigned long *chars )
{
FILE *file;
uint names;
int res;
unsigned long chars;
printf("Counting lines..");
*names = get_line_count(file, chars);
printf("%u\n", *names);
if (argc < 2) {
fprintf(stderr, "Usage: %s <filename>.\n", argv[0]);
return ERR_ARG;
}
if (*names == -1) {
fprintf(stderr, "Error reading domain names from file.\n");
return ERR_FILE_READ;
}
file = fopen(argv[1], "r");
#ifdef CK_TEST_DEBUG
printf("Domains read: %d.\n", *names);
#endif
if (file == NULL) {
fprintf(stderr, "Can't open file: %s.\n", argv[1]);
return ERR_FILE_OPEN;
}
return 0;
}
printf("Counting lines..");
names = get_line_count(file, &chars);
printf("%u\n", names);
/*----------------------------------------------------------------------------*/
if (names == -1) {
fprintf(stderr, "Error reading domain names from file.\n");
return ERR_FILE_READ;
}
int fill_hash_table( ck_hash_table *table, FILE *file, uint names,
unsigned long chars )
{
// hash the domain names
int res = hash_from_file(file, table, names, chars);
#ifdef TEST_DEBUG
printf("Domains read: %d.\n", names);
#endif
if (res == 0) {
printf("Successful.\n");
printf("Number of items in the buffer: %u\n", table->buf_i);
} else {
fprintf(stderr, "Error inserting names to the hash table.\n");
return res;
}
table = ck_create_table(names, destroy_items);
return 0;
}
if (table == NULL) {
fprintf(stderr, "Error creating hash table.\n");
return ERR_TABLE_CREATE;
}
/*----------------------------------------------------------------------------*/
fseek(file, 0, SEEK_SET);
int create_and_fill_table( ck_hash_table **table, FILE *file )
{
uint names;
unsigned long chars;
int res;
// hash the domain names
res = hash_from_file(file, table, names, chars);
if ((res = count_domain_names(file, &names, &chars)) != 0) {
fclose(file);
return ERR_COUNT;
}
if (res == 0) {
printf("Successful.\n");
printf("Number of items in the buffer: %u\n", table->buf_i);
} else {
fprintf(stderr, "Error inserting names to the hash table.\n");
}
fseek(file, 0, SEEK_SET);
*table = ck_create_table(names, destroy_items);
fseek(file, 0, SEEK_SET);
if (*table == NULL) {
fprintf(stderr, "Error creating hash table.\n");
return ERR_TABLE_CREATE;
}
// testing lookup
res = test_lookup_from_file(table, file);
if ((res = fill_hash_table(*table, file, names, chars)) != 0) {
ck_destroy_table(table);
return ERR_FILL;
}
if (res != 0) {
ck_destroy_table(&table);
return res;
return 0;
}
/*----------------------------------------------------------------------------*/
int test_hash_table( char *filename )
{
printf("Testing hash table...\n\n");
printf("Opening file...");
FILE *file = fopen(filename, "r");
if (file == NULL) {
fprintf(stderr, "Can't open file: %s.\n", filename);
return ERR_FILE_OPEN;
}
// launch socket manager for listening
printf("Done.\n");
printf("Creating and filling the table...\n\n");
uint res = create_and_fill_table(&table, file);
switch (res) {
case ERR_FILL:
ck_destroy_table(&table);
case ERR_COUNT:
case ERR_TABLE_CREATE:
return res;
}
printf("\nDone.\n\n");
fseek(file, 0, SEEK_SET);
printf("Testing lookup...\n\n");
res = test_lookup_from_file(table, file);
printf("\nDone. Result: %u\n\n", res);
ck_destroy_table(&table);
fclose(file);
return res;
}
/*----------------------------------------------------------------------------*/
int start_server( char *filename )
{
printf("Starting server...\n\n");
printf("Opening file...");
FILE *file = fopen(filename, "r");
if (file == NULL) {
fprintf(stderr, "Can't open file: %s.\n", filename);
return ERR_FILE_OPEN;
}
printf("Done.\n\n");
printf("Creating and filling the table...\n\n");
uint res = create_and_fill_table(&table, file);
switch (res) {
case ERR_FILL:
ck_destroy_table(&table);
case ERR_COUNT:
case ERR_TABLE_CREATE:
printf("Error %u.\n", res);
return res;
}
printf("\nDone.\n\n");
fclose(file);
printf("Creating socket manager...\n\n");
sm_manager *manager = sm_create(PORT, THREAD_COUNT, answer_request);
if (manager == NULL) {
ck_destroy_table(&table);
return -1;
}
printf("\nDone.\n\n");
printf("Starting socket manager...\n");
sm_start(manager);
......
#ifndef CUCKOO_TEST
#define CUCKOO_TEST
/*----------------------------------------------------------------------------*/