⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 storage.cxx

📁 完全免费的邮件发送程序。delphi 6.0
💻 CXX
📖 第 1 页 / 共 2 页
字号:
//-< 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 + -