📄 storage.cxx
字号:
//-< STORAGE.CXX >---------------------------------------------------*--------*
// POST++ Version 1.0 (c) 1998 GARRET * ? *
// (Persistent Object Storage) * /\| *
// * / \ *
// Created: 2-Feb-98 K.A. Knizhnik * / [] \ *
// Last update: 21-Jan-99 K.A. Knizhnik * GARRET *
//-------------------------------------------------------------------*--------*
// Memory allocation, garbage collection, data storing/retrieving
//-------------------------------------------------------------------*--------*
#include "object.h"
simple_mutex storage::global_mutex;
class storage_class_descriptor : public object {
public:
storage_class_descriptor* next;
size_t size;
char name[1];
CLASSINFO(storage_class_descriptor, REF(next));
};
REGISTER(storage_class_descriptor);
static void storage_page_map_constructor(object*) {}
static class_descriptor storage_page_map_class("storage_page_map",
sizeof(storage_page_map),
&storage_page_map_constructor);
long storage::base_address_shift;
gc_segment* storage::gc_stack;
storage* storage::chain;
const int storage::block_chain[32] = {
0, 0, 1, 2, 3, 4, 5, 6, 7, 8,
9, 9, 10, 10, 10, 10, 11, 11, 11, 11,
11, 12, 12, 12, 12, 12, 12, 12, 12, 12,
12, 12
};
const int storage::block_size[32] = {
16, 16, 24, 32, 40, 48, 56, 64, 72, 80,
96, 96, 128, 128, 128, 128, 168, 168, 168, 168,
168, 256, 256, 256, 256, 256, 256, 256, 256, 256,
256, 256
};
inline void storage_header::adjust_references(long shift)
{
int i;
if (page_map != NULL) {
*(char**)&page_map += shift;
}
for (i = items(free_block_chain); --i >= 0;) {
if (free_block_chain[i] != NULL) {
*(char**)&free_block_chain[i] += shift;
}
}
if (free_page_chain != NULL) {
*(char**)&free_page_chain += shift;
}
if (root_object != NULL) {
*(char**)&root_object += shift;
}
if (class_dictionary != NULL) {
*(char**)&class_dictionary += shift;
}
for (i = n_static_data; --i >= 0;) {
*(char**)&static_data[i] += shift;
}
}
void storage::handle_error(const char* func)
{
file::msg_buf buf;
data_file.get_error_text(buf, sizeof buf);
fprintf(stderr, "file::%s: %s\n", func, buf);
abort();
}
bool storage::open(int flags)
{
CS2(global_mutex, mutex);
if (data_file.open((flags & use_transaction_log)
? file::shadow_pages_transaction
: (flags & no_file_mapping)
? file::load_in_memory
: (flags & fault_tolerant)
? file::copy_on_write_map
: file::map_file,
(flags & read_only)
? file::read_only : file::read_write))
{
hdr = (storage_header*)data_file.get_base();
assert((size_t(hdr) & (page_size-1)) == 0/*check proper alignment*/);
if (data_file.get_size() < sizeof(storage_header)) {
if (!data_file.set_size(page_size)) {
handle_error("set_size");
}
if (flags & read_only) {
TRACE_MSG(("Empty file opened in readonly mode\n"));
return false;
}
memset(hdr, 0, page_size);
}
load_class_dictionary();
bool file_updated = false;
if (hdr->base_address != hdr
|| (flags & do_garbage_collection)
|| ((flags & support_virtual_functions)
&& strcmp(hdr->timestamp, file::get_program_timestamp()) != 0))
{
TRACE_MSG(("storage::open: %s\n",
(hdr->base_address != hdr) ? "base_address changed"
: (flags & do_garbage_collection) ? "do garbage collection"
: "executable file and strorage have different timestamps"));
if (flags & read_only) {
if (!data_file.set_protection(file::read_write)) {
handle_error("set_protection");
}
}
if (hdr->base_address != NULL) {
base_address_shift = (char*)hdr - (char*)hdr->base_address;
if (base_address_shift != 0) {
if (flags & fixed) {
TRACE_MSG(("Failed to map to the same address\n"));
return false;
}
TRACE_MSG(("storage::open: adjust references: shift=%ld\n",
shift));
hdr->adjust_references(base_address_shift);
}
if (flags & do_garbage_collection) {
garbage_collection(base_address_shift);
} else {
adjust_references(base_address_shift);
}
base_address_shift = 0;
} else {
// initialize storage
hdr->file_size = page_size;
hdr->version = POST_VERSION;
}
file_updated = true;
hdr->base_address = (void*)hdr;
if (flags & support_virtual_functions) {
strcpy(hdr->timestamp, file::get_program_timestamp());
} else {
*hdr->timestamp = '\0';
}
if (flags & read_only) {
if (!data_file.set_protection(file::read_only)) {
handle_error("set_protection");
}
}
}
curr_free_page = hdr->free_page_chain;
if (!(flags & read_only)) {
file_updated |= update_class_dictionary();
if (file_updated && (flags & use_transaction_log)) {
if (!data_file.commit()) {
handle_error("commit");
}
}
}
next = chain;
chain = this;
return true;
}
return false;
}
void storage::load_class_dictionary()
{
int count = hdr->n_classes + object_header::first_cid;
long shift = (char*)hdr - (char*)hdr->base_address;
storage_class_descriptor* scd;
class_descriptor* cd;
dbs_class_mapping = new class_descriptor*[count + class_descriptor::count];
app_class_mapping = new int[class_descriptor::count];
memset(dbs_class_mapping, 0,
sizeof(class_descriptor*)*(count + class_descriptor::count));
memset(app_class_mapping, 0, sizeof(int)*class_descriptor::count);
cd = &storage_class_descriptor::self_class;
app_class_mapping[cd->id] = object_header::metaclass_cid;
dbs_class_mapping[object_header::metaclass_cid] = cd;
cd = &storage_page_map_class;
app_class_mapping[cd->id] = object_header::page_map_cid;
dbs_class_mapping[object_header::page_map_cid] = cd;
for (scd = hdr->class_dictionary; scd != NULL; scd = scd->next) {
scd = (storage_class_descriptor*)((char*)scd + shift);
count -= 1;
cd = class_descriptor::find_class(scd->name);
#if DEBUG_LEVEL >= DEBUG_CHECK
assert(cd != NULL && cd->size == scd->size);
#endif
if (cd != NULL) {
app_class_mapping[cd->id] = count;
dbs_class_mapping[count] = cd;
}
}
}
bool storage::update_class_dictionary()
{
int count = hdr->n_classes + object_header::first_cid;
int n_stored_classes = 0;
storage_class_descriptor* scd;
class_descriptor* cd;
for (cd = class_descriptor::list; cd != NULL; cd = cd->next) {
if (app_class_mapping[cd->id] == 0) {
app_class_mapping[cd->id] = count;
dbs_class_mapping[count++] = cd;
scd = (storage_class_descriptor*)
_allocate(storage_class_descriptor::self_class.id,
sizeof(storage_class_descriptor)
+ strlen(cd->name));
strcpy(scd->name, cd->name);
scd->size = cd->size;
scd->next = hdr->class_dictionary;
hdr->class_dictionary = scd;
n_stored_classes += 1;
TRACE_MSG(("storage::update_class_dictionary: put class '%s' "
"size=%ld in storage\n", cd->name, cd->size));
}
}
hdr->n_classes = count - object_header::first_cid;
return n_stored_classes != 0;
}
object_header* storage::get_header(object const* obj)
{
object_header* hp;
size_t addr = size_t(obj) - sizeof(object_header);
size_t offs = addr - size_t(hdr);
assert(offs < hdr->file_size);
int page_no = offs / page_size;
if (hdr->page_map == NULL
|| !(hdr->page_map->bits[page_no >> 3] & (1 << (page_no & 7))))
{
hp = (object_header*)(addr & ~(page_size-1));
if (hp->size + sizeof(object_header) <= page_size/2) {
size_t size =
block_size[((hp->size + sizeof(object_header)+7) >> 3) - 1];
if (size & (size-1)) {
offs &= page_size-1; //offset within page
hp = (object_header*)(addr - (offs % size));
} else { // power of 2
hp = (object_header*)(addr & ~(size-1));
}
}
} else { // large object occupies several pages
do {
page_no -= 1;
} while (hdr->page_map->bits[page_no >> 3] & (1 << (page_no & 7)));
hp = (object_header*)((char*)hdr + page_no*page_size);
}
assert(hp->cid != object_header::free_object);
return hp;
}
int storage::garbage_collection()
{
CS2(global_mutex, mutex);
base_address_shift = 0;
return garbage_collection(0);
}
int storage::garbage_collection(long shift)
{
const size_t gc_init_stack_size = 64*1024;
gc_segment* stack_bottom = new gc_segment[gc_init_stack_size];
gc_segment* end_of_stack = stack_bottom + gc_init_stack_size;
gc_segment* sp = stack_bottom;
if (hdr->root_object) {
sp->ptr = (object**)&hdr->root_object;
sp->len = 1;
sp += 1;
// Eliminate shift done by storage_header::adjust_reference
// to make it possible to work with this reference as with other ones
*(char**)&hdr->root_object -= shift;
}
if (hdr->class_dictionary) {
sp->ptr = (object**)&hdr->class_dictionary;
sp->len = 1;
sp += 1;
*(char**)&hdr->class_dictionary -= shift;
}
if (hdr->n_static_data > 0) {
sp->ptr = hdr->static_data;
sp->len = hdr->n_static_data;
sp += 1;
for (int i = hdr->n_static_data; --i >= 0;) {
*(char**)&hdr->static_data[i] -= shift;
}
}
if (hdr->page_map) {
hdr->page_map->cid |= object_header::gc_marked;
}
while (sp != stack_bottom) {
sp -= 1;
object** opp = sp->ptr;
size_t len = sp->len;
do {
if (*opp != NULL) {
*(char**)opp += shift;
object_header* hp = get_header(*opp);
if (!(hp->cid & object_header::gc_marked)) {
class_descriptor* desc = get_object_class(hp->cid);
hp->cid |= object_header::gc_marked;
//
// Number of pointer segments in object is not greater than
// object_size/pointer_size, and so the size of stack
// needed for storing this segments is not more
// than 2 * size of the object.
//
if ((char*)sp + 2*hp->size >= (char*)end_of_stack) {
size_t old_size = sp - stack_bottom;
size_t new_size =
old_size*2 + (hp->size / sizeof(object*));
gc_segment* new_stack = new gc_segment[new_size];
memcpy(new_stack, stack_bottom,
old_size*sizeof(gc_segment));
sp = new_stack + old_size;
delete[] stack_bottom;
stack_bottom = new_stack;
end_of_stack = new_stack + new_size;
}
gc_stack = sp;
desc->constructor((object*)(hp+1));
sp = gc_stack;
}
}
opp += 1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -