#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#include <stdarg.h>
#include "mmap_cache.h"
#include "mmap_cache_internals.h"
MU32 time_override = 0;
void
mmc_set_time_override(MU32 set_time) {
time_override = set_time;
}
char
* def_share_file =
"/tmp/sharefile"
;
MU32 def_init_file = 0;
MU32 def_test_file = 0;
MU32 def_expire_time = 0;
MU32 def_c_num_pages = 89;
MU32 def_c_page_size = 65536;
MU32 def_start_slots = 89;
mmap_cache * mmc_new() {
mmap_cache * cache = (mmap_cache *)
calloc
(1,
sizeof
(mmap_cache));
cache->p_cur = NOPAGE;
cache->c_num_pages = def_c_num_pages;
cache->c_page_size = def_c_page_size;
cache->start_slots = def_start_slots;
cache->expire_time = def_expire_time;
cache->share_file = _mmc_get_def_share_filename(cache);
cache->permissions = 0640;
cache->init_file = def_init_file;
cache->test_file = def_test_file;
return
cache;
}
int
mmc_set_param(mmap_cache * cache,
char
* param,
char
* val) {
if
(!
strcmp
(param,
"init_file"
)) {
cache->init_file =
atoi
(val);
}
else
if
(!
strcmp
(param,
"test_file"
)) {
cache->test_file =
atoi
(val);
}
else
if
(!
strcmp
(param,
"page_size"
)) {
cache->c_page_size =
atoi
(val);
}
else
if
(!
strcmp
(param,
"num_pages"
)) {
cache->c_num_pages =
atoi
(val);
}
else
if
(!
strcmp
(param,
"expire_time"
)) {
cache->expire_time =
atoi
(val);
}
else
if
(!
strcmp
(param,
"share_file"
)) {
cache->share_file = val;
}
else
if
(!
strcmp
(param,
"permissions"
)) {
cache->permissions =
atoi
(val);
}
else
if
(!
strcmp
(param,
"start_slots"
)) {
cache->start_slots =
atoi
(val);
}
else
if
(!
strcmp
(param,
"catch_deadlocks"
)) {
cache->catch_deadlocks =
atoi
(val);
}
else
if
(!
strcmp
(param,
"enable_stats"
)) {
cache->enable_stats =
atoi
(val);
}
else
{
return
_mmc_set_error(cache, 0,
"Bad set_param parameter: %s"
, param);
}
return
0;
}
int
mmc_get_param(mmap_cache * cache,
char
* param) {
if
(!
strcmp
(param,
"page_size"
)) {
return
(
int
)cache->c_page_size;
}
else
if
(!
strcmp
(param,
"num_pages"
)) {
return
(
int
)cache->c_num_pages;
}
else
if
(!
strcmp
(param,
"expire_time"
)) {
return
(
int
)cache->expire_time;
}
else
{
return
_mmc_set_error(cache, 0,
"Bad set_param parameter: %s"
, param);
}
}
int
mmc_init(mmap_cache * cache) {
int
i, do_init;
MU32 c_num_pages, c_page_size;
MU64 c_size;
if
(!cache->share_file) {
return
_mmc_set_error(cache, 0,
"No share file specified"
);
}
c_num_pages = cache->c_num_pages;
ASSERT(c_num_pages >= 1 && c_num_pages <= 1000);
c_page_size = cache->c_page_size;
ASSERT(c_page_size >= 1024 && c_page_size <= 1024*1024*1024);
ASSERT(cache->start_slots >= 10 && cache->start_slots <= 500);
cache->c_size = c_size = (MU64)c_num_pages * c_page_size;
if
( mmc_open_cache_file(cache, &do_init) == -1)
return
-1;
if
( mmc_map_memory(cache) == -1)
return
-1;
if
(do_init) {
_mmc_init_page(cache, -1);
if
( mmc_unmap_memory(cache) == -1)
return
-1;
if
( mmc_map_memory(cache) == -1)
return
-1;
}
if
(cache->test_file) {
for
(i = 0; i < cache->c_num_pages; i++) {
int
lock_page = 0, bad_page = 0;
if
(mmc_lock(cache, i)) {
bad_page = 1;
}
else
{
lock_page = 1;
if
(!_mmc_test_page(cache)) {
bad_page = 1;
}
}
if
(lock_page) {
mmc_unlock(cache);
}
if
(bad_page) {
_mmc_init_page(cache, i);
i--;
}
}
}
return
0;
}
int
mmc_close(mmap_cache *cache) {
int
res;
ASSERT(cache->fh);
ASSERT(cache->mm_var);
ASSERT(cache->p_cur == NOPAGE);
if
(cache->p_cur != NOPAGE) {
mmc_unlock(cache);
}
if
(cache->fh) {
mmc_close_fh(cache);
}
if
(cache->mm_var) {
res = mmc_unmap_memory(cache);
if
(res == -1) {
return
_mmc_set_error(cache,
errno
,
"Mmap of shared file %s failed"
, cache->share_file);
}
}
free
(cache);
return
0;
}
char
* mmc_error(mmap_cache * cache) {
if
(cache->last_error)
return
cache->last_error;
return
"Unknown error"
;
}
int
mmc_lock(mmap_cache * cache, MU32 p_cur) {
MU64 p_offset;
void
* p_ptr;
if
(p_cur == NOPAGE || p_cur > cache->c_num_pages)
return
_mmc_set_error(cache, 0,
"page %u is NOPAGE or larger than number of pages"
, p_cur);
if
(cache->p_cur != NOPAGE)
return
_mmc_set_error(cache, 0,
"page %u is already locked, can't lock multiple pages"
, cache->p_cur);
p_offset = (MU64)p_cur * cache->c_page_size;
p_ptr = PTR_ADD(cache->mm_var, p_offset);
if
(mmc_lock_page(cache, p_offset) == -1)
return
-1;
if
(!(P_Magic(p_ptr) == 0x92f7e3b1))
return
_mmc_set_error(cache, 0,
"magic page start marker not found. p_cur is %u, offset is %llu"
, p_cur, p_offset);
cache->p_num_slots = P_NumSlots(p_ptr);
cache->p_free_slots = P_FreeSlots(p_ptr);
cache->p_old_slots = P_OldSlots(p_ptr);
cache->p_free_data = P_FreeData(p_ptr);
cache->p_free_bytes = P_FreeBytes(p_ptr);
cache->p_n_reads = P_NReads(p_ptr);
cache->p_n_read_hits = P_NReadHits(p_ptr);
if
(cache->p_num_slots < 89 || cache->p_num_slots > cache->c_page_size)
return
_mmc_set_error(cache, 0,
"cache num_slots mistmatch"
);
if
(cache->p_free_slots < 0 || cache->p_free_slots > cache->p_num_slots)
return
_mmc_set_error(cache, 0,
"cache free slots mustmatch"
);
if
(cache->p_old_slots > cache->p_free_slots)
return
_mmc_set_error(cache, 0,
"cache old slots mistmatch"
);
if
(cache->p_free_data + cache->p_free_bytes != cache->c_page_size)
return
_mmc_set_error(cache, 0,
"cache free data mistmatch"
);
ASSERT(P_Magic(p_ptr) == 0x92f7e3b1);
ASSERT(P_NumSlots(p_ptr) >= 89 && P_NumSlots(p_ptr) < cache->c_page_size);
ASSERT(P_FreeSlots(p_ptr) >= 0 && P_FreeSlots(p_ptr) <= P_NumSlots(p_ptr));
ASSERT(P_OldSlots(p_ptr) <= P_FreeSlots(p_ptr));
ASSERT(P_FreeData(p_ptr) + P_FreeBytes(p_ptr) == cache->c_page_size);
cache->p_cur = p_cur;
cache->p_offset = p_offset;
cache->p_base = p_ptr;
cache->p_base_slots = PTR_ADD(p_ptr, P_HEADERSIZE);
ASSERT(_mmc_test_page(cache));
return
0;
}
int
mmc_unlock(mmap_cache * cache) {
ASSERT(cache->p_cur != NOPAGE);
if
(cache->p_changed) {
void
* p_ptr = cache->p_base;
P_NumSlots(p_ptr) = cache->p_num_slots;
P_FreeSlots(p_ptr) = cache->p_free_slots;
P_OldSlots(p_ptr) = cache->p_old_slots;
P_FreeData(p_ptr) = cache->p_free_data;
P_FreeBytes(p_ptr) = cache->p_free_bytes;
P_NReads(p_ptr) = cache->p_n_reads;
P_NReadHits(p_ptr) = cache->p_n_read_hits;
}
ASSERT(_mmc_test_page(cache));
mmc_unlock_page(cache);
return
0;
}
int
mmc_is_locked(mmap_cache * cache) {
return
cache->p_cur != NOPAGE ? 1 : 0;
}
int
mmc_hash(
mmap_cache *cache,
void
*key_ptr,
int
key_len,
MU32 *hash_page, MU32 *hash_slot
) {
MU32 h = 0x92f7e3b1;
unsigned
char
* uc_key_ptr = (unsigned
char
*)key_ptr;
unsigned
char
* uc_key_ptr_end = uc_key_ptr + key_len;
while
(uc_key_ptr != uc_key_ptr_end) {
h = (h << 4) + (h >> 28) + *uc_key_ptr++;
}
*hash_page = h % cache->c_num_pages;
*hash_slot = h / cache->c_num_pages;
return
0;
}
int
mmc_read(
mmap_cache *cache, MU32 hash_slot,
void
*key_ptr,
int
key_len,
void
**val_ptr,
int
*val_len,
MU32 *expire_on_p, MU32 *flags_p
) {
MU32 * slot_ptr;
if
(cache->enable_stats) {
cache->p_changed = 1;
cache->p_n_reads++;
}
slot_ptr = _mmc_find_slot(cache, hash_slot, key_ptr, key_len, 0);
if
(!slot_ptr || *slot_ptr == 0) {
return
-1;
}
else
{
MU32 * base_det = S_Ptr(cache->p_base, *slot_ptr);
MU32 now = time_override ? time_override : (MU32)
time
(0);
MU32 expire_on = S_ExpireOn(base_det);
ASSERT(S_SlotHash(base_det) == hash_slot);
if
(expire_on && now >= expire_on) {
return
-1;
}
S_LastAccess(base_det) = now;
*flags_p = S_Flags(base_det);
*expire_on_p = expire_on;
*val_len = S_ValLen(base_det);
*val_ptr = S_ValPtr(base_det);
if
(cache->enable_stats)
cache->p_n_read_hits++;
return
0;
}
}
int
mmc_write(
mmap_cache *cache, MU32 hash_slot,
void
*key_ptr,
int
key_len,
void
*val_ptr,
int
val_len,
MU32 expire_on, MU32 flags
) {
int
did_store = 0;
MU32 kvlen = KV_SlotLen(key_len, val_len);
MU32 * slot_ptr = _mmc_find_slot(cache, hash_slot, key_ptr, key_len, 1);
if
(!slot_ptr)
return
0;
ROUNDLEN(kvlen);
ASSERT(cache->p_cur != NOPAGE);
if
(*slot_ptr > 1) {
_mmc_delete_slot(cache, slot_ptr);
ASSERT(*slot_ptr == 1);
}
ASSERT(*slot_ptr <= 1);
if
(cache->p_free_bytes >= kvlen) {
MU32 * base_det = PTR_ADD(cache->p_base, cache->p_free_data);
MU32 now = time_override ? time_override : (MU32)
time
(0);
if
(expire_on == (MU32)-1)
expire_on = cache->expire_time ? now + cache->expire_time : 0;
S_LastAccess(base_det) = now;
S_ExpireOn(base_det) = expire_on;
S_SlotHash(base_det) = hash_slot;
S_Flags(base_det) = flags;
S_KeyLen(base_det) = (MU32)key_len;
S_ValLen(base_det) = (MU32)val_len;
memcpy
(S_KeyPtr(base_det), key_ptr, key_len);
memcpy
(S_ValPtr(base_det), val_ptr, val_len);
cache->p_free_slots--;
if
(*slot_ptr == 1) { cache->p_old_slots--; }
*slot_ptr = cache->p_free_data;
cache->p_free_bytes -= kvlen;
cache->p_free_data += kvlen;
cache->p_changed = 1;
did_store = 1;
}
return
did_store;
}
int
mmc_delete(
mmap_cache *cache, MU32 hash_slot,
void
*key_ptr,
int
key_len,
MU32 * flags
) {
MU32 * slot_ptr = _mmc_find_slot(cache, hash_slot, key_ptr, key_len, 2);
if
(!slot_ptr || *slot_ptr == 0) {
return
0;
}
else
{
MU32 * base_det = S_Ptr(cache->p_base, *slot_ptr);
*flags = S_Flags(base_det);
_mmc_delete_slot(cache, slot_ptr);
return
1;
}
}
int
last_access_cmp(
const
void
* a,
const
void
* b) {
MU32 av = S_LastAccess(*(MU32 **)a);
MU32 bv = S_LastAccess(*(MU32 **)b);
if
(av < bv)
return
-1;
if
(av > bv)
return
1;
return
0;
}
int
mmc_calc_expunge(
mmap_cache * cache,
int
mode,
int
len,
MU32 * new_num_slots, MU32 *** to_expunge
) {
double
slots_pct;
ASSERT(cache->p_cur != NOPAGE);
if
(len >= 0) {
MU32 kvlen = KV_SlotLen(len, 0);
ROUNDLEN(kvlen);
slots_pct = (
double
)(cache->p_free_slots - cache->p_old_slots) / cache->p_num_slots;
if
(slots_pct > 0.3 && cache->p_free_bytes >= kvlen)
return
0;
}
{
MU32 num_slots = cache->p_num_slots;
MU32 used_slots = num_slots - cache->p_free_slots;
MU32 * slot_ptr = cache->p_base_slots;
MU32 * slot_end = slot_ptr + num_slots;
MU32 ** copy_base_det = (MU32 **)
calloc
(used_slots,
sizeof
(MU32 *));
MU32 ** copy_base_det_end = copy_base_det + used_slots;
MU32 ** copy_base_det_out = copy_base_det;
MU32 ** copy_base_det_in = copy_base_det + used_slots;
MU32 page_data_size = cache->c_page_size - num_slots * 4 - P_HEADERSIZE;
MU32 in_slots, data_thresh, used_data = 0;
MU32 now = time_override ? time_override : (MU32)
time
(0);
for
(; slot_ptr != slot_end; slot_ptr++) {
MU32 data_offset = *slot_ptr;
MU32 * base_det = S_Ptr(cache->p_base, data_offset);
MU32 expire_on, kvlen;
if
(data_offset <= 1) {
continue
;
}
if
(mode == 1) {
*copy_base_det_out++ = base_det;
continue
;
}
expire_on = S_ExpireOn(base_det);
if
(expire_on && now >= expire_on) {
*copy_base_det_out++ = base_det;
continue
;
}
kvlen = S_SlotLen(base_det);
ROUNDLEN(kvlen);
ASSERT(kvlen <= page_data_size);
used_data += kvlen;
ASSERT(used_data <= page_data_size);
*--copy_base_det_in = base_det;
}
ASSERT(copy_base_det_in == copy_base_det_out);
ASSERT(mode != 1 || copy_base_det_out == copy_base_det_end);
slots_pct = (
double
)(copy_base_det_end - copy_base_det_out) / num_slots;
if
(slots_pct > 0.3 && (page_data_size - used_data > (num_slots + 1) * 4 || mode == 2)) {
num_slots = (num_slots * 2) + 1;
}
page_data_size = cache->c_page_size - num_slots * 4 - P_HEADERSIZE;
if
(mode == 0 || mode == 1) {
*to_expunge = copy_base_det;
*new_num_slots = num_slots;
return
(copy_base_det_out - copy_base_det);
}
in_slots = copy_base_det_end - copy_base_det_in;
qsort
((
void
*)copy_base_det_in, in_slots,
sizeof
(MU32 *), &last_access_cmp);
data_thresh = (MU32)(0.6 * page_data_size);
while
(copy_base_det_in != copy_base_det_end && used_data >= data_thresh) {
MU32 * slot_ptr = *copy_base_det_in;
MU32 kvlen = S_SlotLen(slot_ptr);
ROUNDLEN(kvlen);
ASSERT(kvlen <= page_data_size);
used_data -= kvlen;
ASSERT(used_data >= 0);
copy_base_det_out = ++copy_base_det_in;
}
ASSERT(used_data < page_data_size);
*to_expunge = copy_base_det;
*new_num_slots = num_slots;
return
(copy_base_det_out - copy_base_det);
}
}
int
mmc_do_expunge(
mmap_cache * cache,
int
num_expunge, MU32 new_num_slots, MU32 ** to_expunge
) {
MU32 * base_slots = cache->p_base_slots;
MU32 ** to_keep = to_expunge + num_expunge;
MU32 ** to_keep_end = to_expunge + (cache->p_num_slots - cache->p_free_slots);
MU32 new_used_slots = (to_keep_end - to_keep);
MU32 slot_data_size = new_num_slots * 4;
MU32 * new_slot_data = (MU32 *)
calloc
(1, slot_data_size);
MU32 page_data_size = cache->c_page_size - new_num_slots * 4 - P_HEADERSIZE;
void
* new_kv_data =
calloc
(1, page_data_size);
MU32 new_offset = 0;
memset
(new_slot_data, 0, slot_data_size);
for
(;to_keep < to_keep_end; to_keep++) {
MU32 * old_base_det = *to_keep;
MU32 * new_slot_ptr;
MU32 kvlen;
MU32 slot = S_SlotHash(old_base_det) % new_num_slots;
#ifdef DEBUG
{
MU32 hash_page_dummy, hash_slot;
mmc_hash(cache, S_KeyPtr(old_base_det), S_KeyLen(old_base_det), &hash_page_dummy, &hash_slot);
ASSERT(hash_slot == S_SlotHash(old_base_det));
}
#endif
new_slot_ptr = new_slot_data + slot;
while
(*new_slot_ptr) {
if
(++slot >= new_num_slots) { slot = 0; }
new_slot_ptr = new_slot_data + slot;
}
kvlen = S_SlotLen(old_base_det);
memcpy
(PTR_ADD(new_kv_data, new_offset), old_base_det, kvlen);
*new_slot_ptr = new_offset + new_num_slots * 4 + P_HEADERSIZE;
ROUNDLEN(kvlen);
new_offset += kvlen;
}
ASSERT(new_offset <= page_data_size);
memcpy
(base_slots, new_slot_data, slot_data_size);
memcpy
(base_slots + new_num_slots, new_kv_data, new_offset);
cache->p_num_slots = new_num_slots;
cache->p_free_slots = new_num_slots - new_used_slots;
cache->p_old_slots = 0;
cache->p_free_data = new_offset + new_num_slots * 4 + P_HEADERSIZE;
cache->p_free_bytes = page_data_size - new_offset;
cache->p_changed = 1;
free
(new_kv_data);
free
(new_slot_data);
free
(to_expunge);
ASSERT(_mmc_test_page(cache));
return
0;
}
void
mmc_get_page_details(mmap_cache * cache, MU32 * n_reads, MU32 * n_read_hits) {
*n_reads = cache->p_n_reads;
*n_read_hits = cache->p_n_read_hits;
return
;
}
void
mmc_reset_page_details(mmap_cache * cache) {
cache->p_n_reads = 0;
cache->p_n_read_hits = 0;
cache->p_changed = 1;
return
;
}
mmap_cache_it * mmc_iterate_new(mmap_cache * cache) {
mmap_cache_it * it = (mmap_cache_it *)
calloc
(1,
sizeof
(mmap_cache_it));
it->cache = cache;
it->p_cur = NOPAGE;
return
it;
}
MU32 * mmc_iterate_next(mmap_cache_it * it) {
mmap_cache * cache = it->cache;
MU32 * slot_ptr = it->slot_ptr;
MU32 * base_det;
MU32 expire_on;
MU32 now = time_override ? time_override : (MU32)
time
(0);
while
(1) {
if
(slot_ptr == it->slot_ptr_end) {
if
(it->p_cur == NOPAGE) {
it->p_cur = 0;
}
else
{
mmc_unlock(it->cache);
if
(++it->p_cur == cache->c_num_pages) {
it->p_cur = NOPAGE;
it->slot_ptr = 0;
return
0;
}
}
mmc_lock(it->cache, it->p_cur);
slot_ptr = cache->p_base_slots;
it->slot_ptr_end = slot_ptr + cache->p_num_slots;
continue
;
}
if
(*slot_ptr <= 1) {
slot_ptr++;
continue
;
}
base_det = S_Ptr(cache->p_base, *slot_ptr);
expire_on = S_ExpireOn(base_det);
if
(expire_on && now >= expire_on) {
slot_ptr++;
continue
;
}
break
;
}
it->slot_ptr = ++slot_ptr;
return
base_det;
}
void
mmc_iterate_close(mmap_cache_it * it) {
if
(it->p_cur != NOPAGE) {
mmc_unlock(it->cache);
}
free
(it);
}
void
mmc_get_details(
mmap_cache * cache,
MU32 * base_det,
void
** key_ptr,
int
* key_len,
void
** val_ptr,
int
* val_len,
MU32 * last_access, MU32 * expire_on, MU32 * flags
) {
cache = cache;
*key_ptr = S_KeyPtr(base_det);
*key_len = S_KeyLen(base_det);
*val_ptr = S_ValPtr(base_det);
*val_len = S_ValLen(base_det);
*last_access = S_LastAccess(base_det);
*expire_on = S_ExpireOn(base_det);
*flags = S_Flags(base_det);
}
void
_mmc_delete_slot(
mmap_cache * cache, MU32 * slot_ptr
) {
ASSERT(*slot_ptr > 1);
ASSERT(cache->p_cur != NOPAGE);
*slot_ptr = 1;
cache->p_free_slots++;
cache->p_old_slots++;
cache->p_changed = 1;
}
MU32 * _mmc_find_slot(
mmap_cache * cache, MU32 hash_slot,
void
*key_ptr,
int
key_len,
int
mode
) {
MU32 slots_left, * slots_end;
MU32 * slot_ptr = cache->p_base_slots + (hash_slot % cache->p_num_slots);
MU32 * first_deleted = (MU32 *)0;
slots_left = cache->p_num_slots;
slots_end = cache->p_base_slots + slots_left;
ASSERT(cache->p_cur != NOPAGE);
while
(slots_left--) {
MU32 data_offset = *slot_ptr;
ASSERT(data_offset == 0 || data_offset == 1 ||
((data_offset >= P_HEADERSIZE + cache->p_num_slots*4) &&
(data_offset < cache->c_page_size) &&
((data_offset & 3) == 0)));
if
(data_offset == 0) {
break
;
}
if
(data_offset == 1 && mode == 1 && 0 == first_deleted) {
first_deleted = slot_ptr;
}
if
(data_offset == 1) {
}
else
{
MU32 * base_det = S_Ptr(cache->p_base, data_offset);
MU32 fkey_len = S_KeyLen(base_det);
if
(fkey_len == (MU32)key_len && !
memcmp
(key_ptr, S_KeyPtr(base_det), key_len)) {
return
slot_ptr;
}
}
if
(++slot_ptr == slots_end) { slot_ptr = cache->p_base_slots; }
ASSERT(slot_ptr >= cache->p_base_slots && slot_ptr < slots_end);
}
if
(++slots_left == 0) slot_ptr = 0;
if
(1 == mode && 0 != first_deleted)
return
first_deleted;
else
return
slot_ptr;
}
void
_mmc_init_page(mmap_cache * cache, MU32 p_cur) {
MU32 start_page = p_cur, end_page = p_cur+1;
if
(p_cur == NOPAGE) {
start_page = 0;
end_page = cache->c_num_pages;
}
for
(p_cur = start_page; p_cur < end_page; p_cur++) {
MU64 p_offset = (MU64)p_cur * cache->c_page_size;
void
* p_ptr = PTR_ADD(cache->mm_var, p_offset);
memset
(p_ptr, 0, cache->c_page_size);
P_Magic(p_ptr) = 0x92f7e3b1;
P_NumSlots(p_ptr) = cache->start_slots;
P_FreeSlots(p_ptr) = cache->start_slots;
P_OldSlots(p_ptr) = 0;
P_FreeData(p_ptr) = P_HEADERSIZE + cache->start_slots * 4;
P_FreeBytes(p_ptr) = cache->c_page_size - P_FreeData(p_ptr);
P_NReads(p_ptr) = 0;
P_NReadHits(p_ptr) = 0;
}
}
int
_mmc_test_page(mmap_cache * cache) {
MU32 * slot_ptr = cache->p_base_slots;
MU32 count_free = 0, count_old = 0, max_data_offset = 0;
MU32 data_size = cache->c_page_size;
ASSERT(cache->p_cur != NOPAGE);
if
(cache->p_cur == NOPAGE)
return
0;
for
(; slot_ptr < cache->p_base_slots + cache->p_num_slots; slot_ptr++) {
MU32 data_offset = *slot_ptr;
ASSERT(data_offset == 0 || data_offset == 1 ||
(data_offset >= P_HEADERSIZE + cache->p_num_slots * 4 &&
data_offset < cache->c_page_size));
if
(!(data_offset == 0 || data_offset == 1 ||
(data_offset >= P_HEADERSIZE + cache->p_num_slots * 4 &&
data_offset < cache->c_page_size)))
return
0;
if
(data_offset == 1) {
count_old++;
}
if
(data_offset <= 1) {
count_free++;
continue
;
}
if
(data_offset > 1) {
MU32 * base_det = S_Ptr(cache->p_base, data_offset);
MU32 last_access = S_LastAccess(base_det);
MU32 expire_on = S_ExpireOn(base_det);
MU32 key_len = S_KeyLen(base_det);
MU32 val_len = S_ValLen(base_det);
MU32 kvlen = S_SlotLen(base_det);
ROUNDLEN(kvlen);
ASSERT(last_access > 1000000000);
if
(!(last_access > 1000000000))
return
0;
ASSERT(expire_on == 0 || (expire_on > 1000000000));
if
(!(expire_on == 0 || (expire_on > 1000000000)))
return
0;
ASSERT(key_len >= 0 && key_len < data_size);
if
(!(key_len >= 0 && key_len < data_size))
return
0;
ASSERT(val_len >= 0 && val_len < data_size);
if
(!(val_len >= 0 && val_len < data_size))
return
0;
ASSERT(kvlen >= 4*4 && kvlen < data_size);
if
(!(kvlen >= 4*4 && kvlen < data_size))
return
0;
if
(data_offset + kvlen > max_data_offset) {
max_data_offset = data_offset + kvlen;
}
{
MU32 hash_page, hash_slot, * find_slot_ptr;
mmc_hash(cache, S_KeyPtr(base_det), (
int
)key_len,
&hash_page, &hash_slot);
ASSERT(hash_slot == S_SlotHash(base_det));
if
(!(hash_slot == S_SlotHash(base_det)))
return
0;
find_slot_ptr = _mmc_find_slot(cache, hash_slot, S_KeyPtr(base_det), key_len, 0);
ASSERT(find_slot_ptr == slot_ptr);
if
(!(find_slot_ptr == slot_ptr))
return
0;
}
}
}
ASSERT(count_free == cache->p_free_slots);
if
(!(count_free == cache->p_free_slots))
return
0;
ASSERT(count_old == cache->p_old_slots);
if
(!(count_old == cache->p_old_slots))
return
0;
ASSERT(cache->p_free_data >= max_data_offset);
if
(!(cache->p_free_data >= max_data_offset))
return
0;
return
1;
}
int
_mmc_dump_page(mmap_cache * cache) {
MU32 slot;
ASSERT(cache->p_cur != NOPAGE);
printf
(
"PageNum: %d\n"
, cache->p_cur);
printf
(
"\n"
);
printf
(
"PageSize: %d\n"
, cache->c_page_size);
printf
(
"BasePage: %p\n"
, cache->p_base);
printf
(
"BaseSlots: %p\n"
, cache->p_base_slots);
printf
(
"\n"
);
printf
(
"NumSlots: %d\n"
, cache->p_num_slots);
printf
(
"FreeSlots: %d\n"
, cache->p_free_slots);
printf
(
"OldSlots: %d\n"
, cache->p_old_slots);
printf
(
"FreeData: %d\n"
, cache->p_free_data);
printf
(
"FreeBytes: %d\n"
, cache->p_free_bytes);
for
(slot = 0; slot < cache->p_num_slots; slot++) {
MU32 * slot_ptr = cache->p_base_slots + slot;
printf
(
"Slot: %d; OF=%d; "
, slot, *slot_ptr);
if
(*slot_ptr > 1) {
MU32 * base_det = S_Ptr(cache->p_base, *slot_ptr);
MU32 key_len = S_KeyLen(base_det);
MU32 val_len = S_ValLen(base_det);
char
key[256], val[256];
printf
(
"LA=%d, ET=%d, HS=%d, FL=%d\n"
,
S_LastAccess(base_det), S_ExpireOn(base_det),
S_SlotHash(base_det), S_Flags(base_det));
memcpy
(key, S_KeyPtr(base_det), key_len > 256 ? 256 : key_len);
key[key_len] = 0;
memcpy
(val, S_ValPtr(base_det), val_len > 256 ? 256 : val_len);
val[val_len] = 0;
printf
(
" K=%s, V=%s\n"
, key, val);
}
}
return
0;
}