📄 storage.cxx
字号:
} while (--len != 0);
}
delete[] stack_bottom;
gc_stack = NULL;
curr_free_page = NULL;
hdr->free_page_chain = NULL; // will be reconstructed
memset(hdr->free_block_chain, 0, sizeof hdr->free_block_chain);
// ... and sweep
size_t n_deallocated_objects = 0;
size_t n_free_objects = 0;
size_t n_used_objects = 0;
size_t used_size = 0;
storage_free_block* bp = (storage_free_block*)((char*)hdr + page_size);
storage_free_block* end_of_storage =
(storage_free_block*)((char*)hdr + hdr->file_size);
while (bp < end_of_storage) {
size_t size = bp->size + sizeof(object_header);
if (size > page_size/2) { // large object
if (bp->cid & object_header::gc_marked) {
bp->cid &= ~object_header::gc_marked;
n_used_objects += 1;
used_size += size;
} else {
n_deallocated_objects += bp->cid != object_header::free_object;
n_free_objects += 1;
free_page(bp);
}
bp = (storage_free_block*)ALIGN((long)bp + size, page_size);
} else {
int n = ((size+7) >> 3) - 1;
size = block_size[n];
storage_free_block* end_of_page =
(storage_free_block*)((char*)bp + page_size - size + 1);
storage_free_block chain_hdr;
storage_free_block* chain = &chain_hdr;
size_t used = n_used_objects;
do {
if (bp->cid & object_header::gc_marked) {
bp->cid &= ~object_header::gc_marked;
n_used_objects += 1;
used_size += size;
} else {
n_deallocated_objects +=
bp->cid != object_header::free_object;
n_free_objects += 1;
bp->cid = object_header::free_object;
chain = chain->next = bp;
}
bp = (storage_free_block*)((char*)bp+size);
} while (bp < end_of_page);
if (used == n_used_objects) {
// there are no used objects at this page
free_page(chain_hdr.next); // free the whole page
} else {
chain->next = hdr->free_block_chain[block_chain[n]];
hdr->free_block_chain[block_chain[n]] = chain_hdr.next;
}
bp = (storage_free_block*)ALIGN((long)bp, page_size);
}
}
TRACE_MSG(("Free %ld objects\n"
"Total in storage %ld free and %ld used objects\n"
"Currently %ld bytes out of %ld are used\n",
n_deallocated_objects, n_free_objects, n_used_objects,
used_size, hdr->file_size));
return n_deallocated_objects;
}
inline void storage::call_constructor(object_header* hp)
{
get_object_class(hp->cid)->constructor((object*)(hp+1));
}
void storage::adjust_references(long shift)
{
storage_free_block* bp = (storage_free_block*)((char*)hdr + page_size);
storage_free_block* end_of_storage =
(storage_free_block*)((char*)hdr + hdr->file_size);
if (shift == 0) { // minimize number of modified objects
do {
size_t size = bp->size + sizeof(object_header);
if (size > page_size/2) { // large object
if (bp->cid != object_header::free_object) {
call_constructor(bp);
}
bp = (storage_free_block*)ALIGN((long)bp + size, page_size);
} else {
size = block_size[((size+7) >> 3) - 1];
storage_free_block* end_of_page =
(storage_free_block*)((char*)bp + page_size - size + 1);
do {
if (bp->cid != object_header::free_object) {
call_constructor(bp);
}
bp = (storage_free_block*)((char*)bp+size);
} while (bp < end_of_page);
bp = (storage_free_block*)ALIGN((long)bp, page_size);
}
} while (bp < end_of_storage);
} else { // shift != 0
do {
size_t size = bp->size + sizeof(object_header);
if (size > page_size/2) { // large object
if (bp->cid == object_header::free_object) {
if (bp->next != NULL) {
*(char**)&bp->next += shift;
}
} else {
call_constructor(bp);
}
bp = (storage_free_block*)ALIGN((long)bp + size, page_size);
} else {
size = block_size[((size+7) >> 3) - 1];
storage_free_block* end_of_page =
(storage_free_block*)((char*)bp + page_size - size + 1);
do {
if (bp->cid == object_header::free_object) {
if (bp->next != NULL) {
*(char**)&bp->next += shift;
}
} else {
call_constructor(bp);
}
bp = (storage_free_block*)((char*)bp+size);
} while (bp < end_of_page);
bp = (storage_free_block*)ALIGN((long)bp, page_size);
}
} while (bp < end_of_storage);
}
}
void storage::flush()
{
CS(mutex);
if (!data_file.flush()) {
handle_error("flush");
}
}
void storage::commit()
{
CS(mutex);
if (!data_file.commit()) {
handle_error("commit");
}
}
void storage::rollback()
{
CS(mutex);
if (!data_file.rollback()) {
handle_error("rollback");
} else {
curr_free_page = hdr->free_page_chain;
}
}
void storage::close()
{
CS2(global_mutex, mutex);
delete[] app_class_mapping;
delete[] dbs_class_mapping;
storage *sp, **spp = &chain;
while ((sp = *spp) != this) {
spp = &sp->next;
}
*spp = sp->next;
if (!data_file.close()) {
handle_error("close");
}
}
void* storage::alloc_page(int cid, size_t size)
{
storage_free_block* bp = NULL;
size_t aligned_size = ALIGN(size + sizeof(object_header), page_size);
if (hdr->free_page_chain != NULL) {
storage_free_block** bpp = &curr_free_page->next;
while ((bp = *bpp) != NULL && bp->size < size) {
bpp = &bp->next;
}
if (bp == NULL) {
bpp = &hdr->free_page_chain;
storage_free_block* save_next = curr_free_page->next;
curr_free_page->next = NULL;
while ((bp = *bpp) != NULL && bp->size < size) {
bpp = &bp->next;
}
curr_free_page->next = save_next;
}
if (bp != NULL) {
if (bp->size > aligned_size) {
curr_free_page = bp;
bp->size -= aligned_size;
bp = (storage_free_block*)
((char*)bp + bp->size + sizeof(object_header));
} else {
*bpp = bp->next;
curr_free_page = bp->next ? bp->next : hdr->free_page_chain;
}
}
}
if (bp == NULL) {
bp = (storage_free_block*)((char*)hdr + hdr->file_size);
hdr->file_size += aligned_size;
if (!data_file.set_size(hdr->file_size)) {
handle_error("set_size");
}
if (hdr->page_map != NULL && cid != object_header::page_map_cid) {
size_t old_map_size = hdr->page_map->size;
if (hdr->file_size > old_map_size*page_size*8) {
// file_size+map_size+map_header >= page_size*8*map_size
size_t new_map_size =
(hdr->file_size + sizeof(object_header) + page_size*8-2)
/ (page_size*8 - 1);
// reserve space for future
new_map_size = ALIGN(new_map_size + sizeof(object_header),
page_size)*2 - sizeof(object_header);
TRACE_MSG(("storage::alloc: reallocate page map, old size=%ld,"
" new size=%ld\n", old_map_size, new_map_size));
storage_page_map* new_map = (storage_page_map*)
((char*)alloc_page(object_header::page_map_cid,
new_map_size)-sizeof(object_header));
memcpy(new_map->bits, hdr->page_map->bits, old_map_size);
memset(new_map->bits + old_map_size, 0,
new_map_size - old_map_size);
free_page(hdr->page_map);
hdr->page_map = new_map;
}
}
}
bp->cid = cid;
bp->size = size;
if (size + sizeof(object_header) <= page_size/2) {
int n = ((size + sizeof(object_header) + 7) >> 3) - 1;
size = block_size[n];
storage_free_block* end_of_page =
(storage_free_block*)((char*)bp + page_size - size + 1);
storage_free_block* cp = (storage_free_block*)((char*)bp + size);
do {
cp->cid = object_header::free_object;
cp = cp->next = (storage_free_block*)((char*)cp + size);
} while (cp < end_of_page);
cp = (storage_free_block*)((char*)cp - size);
cp->next = hdr->free_block_chain[block_chain[n]];
hdr->free_block_chain[block_chain[n]] =
(storage_free_block*)((char*)bp+size);
} else if (aligned_size > page_size && cid != object_header::page_map_cid){
if (hdr->page_map == NULL) {
// file_size+map_size+map_header >= page_size*8*map_size
size_t map_size =
(hdr->file_size+sizeof(object_header)+page_size*8-2)
/ (page_size*8 - 1);
map_size = ALIGN(map_size + sizeof(object_header), page_size)
* init_page_map_size - sizeof(object_header);
TRACE_MSG(("storage::alloc: allocate page map, size=%ld\n",
map_size));
hdr->page_map = (storage_page_map*)
((char*)alloc_page(object_header::page_map_cid, map_size)
- sizeof(object_header));
memset(hdr->page_map->bits, 0, map_size);
}
int page_no = size_t((char*)bp - (char*)hdr) / page_size;
int n_pages = aligned_size / page_size - 1;
do {
page_no += 1;
hdr->page_map->bits[page_no >> 3] |= 1 << (page_no & 7);
} while (--n_pages != 0);
}
return (object_header*)bp+1;
}
void storage::free_page(object_header* hp)
{
storage_free_block *bp, *prev;
storage_free_block *fp = (storage_free_block*)hp;
if (curr_free_page != NULL && curr_free_page < fp) {
prev = curr_free_page;
bp = prev->next;
} else {
prev = NULL;
bp = hdr->free_page_chain;
}
while (bp != NULL && bp < fp) {
prev = bp;
bp = bp->next;
}
assert(bp != fp/*object can't be deallocated twice*/);
size_t aligned_size = ALIGN(fp->size + sizeof(object_header), page_size);
fp->size = aligned_size - sizeof(object_header);
if (aligned_size > page_size
&& fp->cid != object_header::free_object // reconstruction of free list
&& fp->cid != object_header::page_map_cid) // allocation of page map
{
assert(hdr->page_map != NULL);
int page_no = size_t((char*)fp - (char*)hdr) / page_size;
int n_pages = aligned_size / page_size - 1;
do {
page_no += 1;
hdr->page_map->bits[page_no >> 3] &= ~(1 << (page_no & 7));
} while (--n_pages != 0);
}
fp->cid = object_header::free_object;
fp->next = bp;
if (prev == NULL) {
hdr->free_page_chain = fp;
} else {
if ((char*)prev + prev->size + sizeof(object_header) == (char*)fp) {
prev->size += fp->size + sizeof(object_header);
fp = prev;
} else {
prev->next = fp;
}
}
if ((char*)fp + fp->size + sizeof(object_header) == (char*)bp) {
fp->size += bp->size + sizeof(object_header);
fp->next = bp->next;
}
curr_free_page = fp;
}
char* storage::get_error_text(char* buf, size_t buf_size)
{
return data_file.get_error_text(buf, buf_size);
}
storage::~storage() {}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -