#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#if !defined(WIN32) || defined(CYGWIN)
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#endif
#ifdef DEBUG
#define ASSERT(x) assert(x)
#include <assert.h>
#else
#define ASSERT(x)
#endif
#ifndef WIN32
#include <sys/wait.h>
#else
#include <stdlib.h>
#include <stdio.h>
#include <windows.h>
double
last_rand;
double
drand48(
void
) {
last_rand =
rand
() / (
double
)(RAND_MAX+1);
ASSERT(last_rand < 1);
return
last_rand;
}
#endif
#include <time.h>
#include "mmap_cache.h"
void
* Get(mmap_cache * cache,
void
* key_ptr,
int
key_len,
int
* val_len) {
int
found;
void
* val_ptr, * val_rtn_ptr = 0;
MU32 hash_page, hash_slot, flags;
mmc_hash(cache, key_ptr, key_len, &hash_page, &hash_slot);
mmc_lock(cache, hash_page);
found = mmc_read(cache, hash_slot, key_ptr, key_len, &val_ptr, val_len, &flags);
if
(found == -1) {
}
else
{
val_rtn_ptr = (
void
*)
malloc
(*val_len);
memcpy
(val_rtn_ptr, val_ptr, *val_len);
}
mmc_unlock(cache);
return
val_rtn_ptr;
}
void
Set(mmap_cache * cache,
void
* key_ptr,
int
key_len,
void
* val_ptr,
int
val_len) {
MU32 hash_page, hash_slot, flags = 0, new_num_slots, ** expunge_items = 0;
int
num_expunge;
mmc_hash(cache, key_ptr, key_len, &hash_page, &hash_slot);
mmc_lock(cache, hash_page);
num_expunge = mmc_calc_expunge(cache, 2, key_len + val_len, &new_num_slots, &expunge_items);
if
(expunge_items) {
mmc_do_expunge(cache, num_expunge, new_num_slots, expunge_items);
}
mmc_write(cache, hash_slot, key_ptr, key_len, val_ptr, val_len, 60, flags);
mmc_unlock(cache);
}
char
* rand_str(
int
nchar) {
unsigned
char
* buf = (unsigned
char
*)
malloc
(nchar + 1);
int
i;
for
(i = 0; i < nchar; i++) {
buf[i] = (
char
)(
rand
() % 26) +
'A'
;
}
buf[i] = 0;
return
(
char
*)buf;
}
char
buf[65537];
int
BasicTests(mmap_cache * cache) {
int
val_len, i;
void
* val_ptr;
printf
(
"Basic tests\n"
);
ASSERT(!Get(cache,
""
, 0, &val_len));
ASSERT(!Get(cache,
" "
, 0, &val_len));
for
(i = 0; i < 65536; i++) { buf[i] =
' '
; }
ASSERT(!Get(cache, buf, 1024, &val_len));
ASSERT(!Get(cache, buf, 65536, &val_len));
Set(cache,
""
, 0,
"abc"
, 3);
ASSERT(!
memcmp
(val_ptr = Get(cache,
""
, 0, &val_len),
"abc"
, 3) && val_len == 3);
free
(val_ptr);
Set(cache,
" "
, 1,
"def"
, 3);
ASSERT(!
memcmp
(val_ptr = Get(cache,
" "
, 1, &val_len),
"def"
, 3) && val_len == 3);
free
(val_ptr);
Set(cache, buf, 1024,
"ghi"
, 3);
ASSERT(!
memcmp
(val_ptr = Get(cache, buf, 1024, &val_len),
"ghi"
, 3) && val_len == 3);
free
(val_ptr);
Set(cache, buf, 65536,
"jkl"
, 3);
ASSERT(!Get(cache, buf, 65536, &val_len));
Set(cache,
"abc"
, 3,
""
, 0);
ASSERT((val_ptr = Get(cache,
"abc"
, 3, &val_len)) && val_len == 0);
free
(val_ptr);
Set(cache,
"def"
, 3,
"x"
, 1);
ASSERT(!
memcmp
(val_ptr = Get(cache,
"def"
, 3, &val_len),
"x"
, 1) && val_len == 1);
free
(val_ptr);
for
(i = 0; i < 1024; i++) { buf[i] =
'y'
; }
buf[0] =
'z'
; buf[1023] =
'w'
;
Set(cache,
"ghi"
, 3, buf, 1024);
ASSERT(!
memcmp
(val_ptr = Get(cache,
"ghi"
, 3, &val_len), buf, 1024) && val_len == 1024);
free
(val_ptr);
Set(cache,
"jkl"
, 3, buf, 65536);
ASSERT(!Get(cache,
"jkl"
, 3, &val_len));
return
0;
}
int
LinearTests(mmap_cache * cache) {
int
i, gl;
char
* str1, * str2, * str3;
printf
(
"Linear tests\n"
);
for
(i = 0; i < 100000; i++) {
str1 = rand_str(10);
str2 = rand_str(10);
Set(cache, str1,
strlen
(str1)+1, str2,
strlen
(str2)+1);
str3 = Get(cache, str1,
strlen
(str1)+1, &gl);
ASSERT(
strlen
(str2)+1 == gl);
ASSERT(!
memcmp
(str2, str3,
strlen
(str2)+1));
free
(str1);
free
(str2);
free
(str3);
if
(i % 1000 == 0) {
printf
(
"%d\n"
, i);
}
}
}
int
EdgeTests() {
return
0;
}
typedef
struct
key_list {
int
n_keys;
int
buf_size;
char
** keys;
} key_list;
key_list * kl_new() {
key_list * kl = (key_list *)
malloc
(
sizeof
(key_list));
kl->buf_size = 8;
kl->keys = (
char
**)
malloc
(
sizeof
(
char
*) * kl->buf_size);
kl->n_keys = 0;
return
kl;
}
void
kl_push(key_list * kl,
char
* key) {
if
(kl->n_keys < kl->buf_size) {
kl->keys[kl->n_keys++] = key;
return
;
}
kl->buf_size *= 2;
kl->keys = (
char
**)
realloc
(kl->keys,
sizeof
(
char
*) * kl->buf_size);
kl->keys[kl->n_keys++] = key;
return
;
}
void
kl_free(key_list * kl) {
int
i;
for
(i = 0; i < kl->n_keys; i++) {
free
(kl->keys[i]);
}
}
int
urand_fh = 0;
void
RandSeed() {
#ifdef WIN32
#else
char
buf[8];
if
(!urand_fh) {
urand_fh = open(
"/dev/urandom"
, O_RDONLY);
}
read(urand_fh, buf, 8);
srand48(*(
long
int
*)buf);
#endif
}
int
RepeatMixTests(mmap_cache * cache,
double
ratio, key_list * kl) {
int
i, val_len;
int
read = 0, read_hit = 0;
char
valbuf[256];
printf
(
"Repeat mix tests\n"
);
for
(i = 0; i < 10000; i++) {
if
(drand48() < ratio) {
char
* k = kl->keys[(
int
)(drand48() * kl->n_keys)];
void
* v = Get(cache, k,
strlen
(k), &val_len);
read++;
if
(!v) {
continue
; }
read_hit++;
memcpy
(valbuf, v+10,
strlen
(k));
valbuf[
strlen
(k)] =
'\0'
;
ASSERT(!
memcmp
(valbuf, k,
strlen
(k)));
free
(v);
}
else
{
char
* k = rand_str(10 + (
int
)(drand48() * 10));
char
* v = rand_str(10);
char
* ve = rand_str((
int
)(drand48() * 200));
strcpy
(valbuf, v);
strcat
(valbuf, k);
strcat
(valbuf, ve);
kl_push(kl, k);
Set(cache, k,
strlen
(k), valbuf,
strlen
(valbuf));
free
(ve);
free
(v);
}
}
if
(read) {
printf
(
"Read hit pct: %5.3f\n"
, (
double
)read_hit/read);
}
return
1;
}
void
IteratorTests(mmap_cache * cache) {
MU32 * entry_ptr;
void
* key_ptr, * val_ptr;
int
key_len, val_len;
MU32 last_access, expire_time, flags;
mmap_cache_it * it = mmc_iterate_new(cache);
printf
(
"Iterator tests\n"
);
while
((entry_ptr = mmc_iterate_next(it))) {
mmc_get_details(cache, entry_ptr,
&key_ptr, &key_len, &val_ptr, &val_len,
&last_access, &expire_time, &flags);
ASSERT(key_len >= 10 && key_len <= 20);
ASSERT(val_len >= 20 && val_len <= 240);
ASSERT(last_access >= 1000000 && last_access <=
time
(0));
}
mmc_iterate_close(it);
}
int
ForkTests(mmap_cache * cache, key_list * kl) {
#ifndef WIN32
int
pid, j, k, kid, kids[20], nkids = 0, status;
struct
timeval timeout = { 0, 1000 };
for
(j = 0; j < 8; j++) {
if
(!(pid = fork())) {
RandSeed();
RepeatMixTests(cache, 0.4, kl);
exit
(0);
}
kids[nkids++] = pid;
select(0, 0, 0, 0, &timeout);
}
do
{
kid = waitpid(-1, &status, 0);
for
(j = 0, k = 0; j < nkids; j++) {
if
(kids[j] != kid) { k++; }
kids[j] = kids[k];
}
nkids--;
}
while
(kid > 0 && nkids);
return
0;
#else
#endif
}
int
main(
int
argc,
char
** argv) {
int
res;
key_list * kl;
mmap_cache * cache;
cache = mmc_new();
mmc_set_param(cache,
"init_file"
,
"1"
);
res = mmc_init(cache);
kl = kl_new();
BasicTests(cache);
LinearTests(cache);
mmc_close(cache);
cache = mmc_new();
mmc_set_param(cache,
"init_file"
,
"1"
);
res = mmc_init(cache);
RepeatMixTests(cache, 0.0, kl);
RepeatMixTests(cache, 0.5, kl);
RepeatMixTests(cache, 0.8, kl);
IteratorTests(cache);
ForkTests(cache, kl);
kl_free(kl);
mmc_close(cache);
cache = mmc_new();
mmc_set_param(cache,
"init_file"
,
"1"
);
mmc_set_param(cache,
"page_size"
,
"8192"
);
res = mmc_init(cache);
kl = kl_new();
BasicTests(cache);
RepeatMixTests(cache, 0.0, kl);
RepeatMixTests(cache, 0.5, kl);
RepeatMixTests(cache, 0.8, kl);
ForkTests(cache, kl);
kl_free(kl);
mmc_close(cache);
return
0;
}