📄 storage.h
字号:
//-< STORAGE.H >-----------------------------------------------------*--------*
// 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 *
//-------------------------------------------------------------------*--------*
// Storage interface
//-------------------------------------------------------------------*--------*
#ifndef __STORAGE_H__
#define __STORAGE_H__
#define POST_VERSION 135 // 1.35
#include "file.h"
const size_t defaultMaxDatabaseSize = 8*1024*1024;
const int maxStaticData = 32;
#if defined(_WIN32)
class simple_mutex {
CRITICAL_SECTION cs;
public:
void enter() {
EnterCriticalSection(&cs);
}
void leave() {
LeaveCriticalSection(&cs);
}
simple_mutex() {
InitializeCriticalSection(&cs);
}
~simple_mutex() {
DeleteCriticalSection(&cs);
}
};
#elif defined(_REENTRANT)
#include <pthread.h>
class simple_mutex {
pthread_mutex_t cs;
public:
void enter() {
pthread_mutex_lock(&cs);
}
void leave() {
pthread_mutex_unlock(&cs);
}
simple_mutex() {
pthread_mutex_init(&cs, NULL);
}
~simple_mutex() {
pthread_mutex_destroy(&cs);
}
};
#else
class simple_mutex {
public:
void enter() {}
void leave() {}
};
#endif
class critical_section {
simple_mutex& mutex;
public:
critical_section(simple_mutex& cs) : mutex(cs) {
cs.enter();
}
~critical_section() {
mutex.leave();
}
};
#define CS(mutex) critical_section __cs(mutex)
#define CS2(mutex1, mutex2) critical_section __cs1(mutex1), __cs2(mutex2)
class object;
class class_descriptor;
struct object_header {
enum {
free_object = 0,
metaclass_cid = 1,
page_map_cid = 2,
first_cid = 3,
gc_marked = 0x80000000
};
int cid;
unsigned size;
};
struct storage_free_block : public object_header {
storage_free_block* next;
};
class storage_class_descriptor;
class storage_page_map : public object_header {
public:
//
// All pages except first occupied by large object are marked with non-zero
// bit in this bitmap. Bits correspond to all other pages are zero.
//
char bits[1];
};
struct storage_header : public file_header {
object* root_object;
size_t n_classes;
storage_class_descriptor* class_dictionary;
int version;
storage_page_map* page_map;
storage_free_block* free_page_chain;
storage_free_block* free_block_chain[13];
char timestamp[32];
int n_static_data;
object* static_data[maxStaticData];
void adjust_references(long shift);
};
struct gc_segment {
object** ptr;
size_t len;
};
class storage {
friend class object;
public:
static long base_address_shift;
static gc_segment* gc_stack;
enum open_flags {
use_transaction_log = 0x01, // apply all changes as transactions
no_file_mapping = 0x02, // do not use file mapping mechanism
fault_tolerant = 0x04, // preserve storage consistency
read_only = 0x08, // read only file view
support_virtual_functions = 0x10, // storage objects contain virt.func.
do_garbage_collection = 0x20, // perform GC on loading
fixed = 0x40 // always map to the same address
};
virtual bool open(int flags = 0);
//
// Commit current transaction: save all modified pages in data file and
// truncate transaction log. This function works only in
// in transaction mode (when flag use_transaction_log is set).
// Commit is implicitly called by close().
//
virtual void commit();
//
// Rollback current transaction. This function works only in
// in transaction mode (when flag use_transaction_log is set).
//
virtual void rollback();
//
// Flush all changes on disk.
// Behavior of this function depends on storage mode:
// 1. In transaction mode this function is equivalent to commit().
// 2. In other modes this functions performs atomic update of storage file
// by flushing data to temporary file and then renaming it to original
// one. All modified objects will not be written in data file until
// flush().
//
virtual void flush();
//
// Close storage. To store modified objects you should first call flush(),
// otherwise all changes will be lost.
//
virtual void close();
//
// Free all objects unreachable from the storage root object.
// This function will be called from open() if 'do_garbage_collection'
// attribute is specified. It is also possible to call this function
// explicitly, but you should be sure that no program variable points
// to object unreachable from the storage root.
// Method returns number of deallocated objects. Even if you are using
// explicit memory deallocation you can call this method to search for
// memory leak and check reference consisteny.
//
virtual int garbage_collection();
//
// Report error in storage method "func". Applciation can override this
// method to perform application dependent error handling.
// Default implementation of this method out put message and abort
// application
//
virtual void handle_error(const char* func);
void set_root_object(void* obj) {
hdr->root_object = (object*)obj;
}
void* get_root_object() const {
return hdr->root_object;
}
void set_version(int version) {
hdr->version = version;
}
int get_version() const {
return hdr->version;
}
void begin_static_data() {
static_data = true;
static_data_index = 0;
}
void end_static_data() {
static_data = false;
}
void* get_static_data() {
if (static_data && static_data_index < hdr->n_static_data) {
return hdr->static_data[static_data_index++];
}
return NULL;
}
void set_static_data(void* obj) {
if (static_data) {
assert(hdr->n_static_data < maxStaticData);
hdr->static_data[static_data_index] = (object*)obj;
hdr->n_static_data = ++static_data_index;
}
}
bool is_static_data(void* obj) {
for (int i = hdr->n_static_data; --i >= 0; ) {
if (hdr->static_data[i] == obj) {
return true;
}
}
return false;
}
static storage* find_storage(object const* obj) {
for (storage* sp = chain; sp != NULL; sp = sp->next) {
if (size_t((char*)obj - (char*)sp->hdr) < sp->hdr->file_size) {
return sp;
}
}
return NULL;
}
static storage* get_current_storage() {
assert(chain == NULL || chain->next == NULL);
return chain;
}
class_descriptor* get_object_class(int cid) const {
return dbs_class_mapping[cid];
}
bool has_object(object const* obj) const {
return size_t((char*)obj - (char*)hdr) < hdr->file_size;
}
char* get_error_text(char* buf, size_t buf_size);
object_header* get_header(object const* obj);
//
// Allocate object in storage.
//
void* allocate(int app_class_id, size_t size) {
CS(mutex);
return _allocate(app_class_id, size);
}
//
// Explicit deallocation of object in storage.
//
void free(object* obj) {
CS(mutex);
object_header* hp = get_header(obj);
if (hp->size + sizeof(object_header) <= page_size/2) {
int n = block_chain[((hp->size+sizeof(object_header)+7) >> 3) - 1];
storage_free_block* bp = (storage_free_block*)hp;
bp->cid = object_header::free_object;
bp->next = hdr->free_block_chain[n];
hdr->free_block_chain[n] = bp;
} else {
free_page(hp);
}
}
//
// Parameter max_file_size specifies maximal data file extension for
// this storage.
// Parameter max_locked_pages is used only in transaction mode and
// specifies number of pages which can be locked in memory to provide
// buffering sadow pages writes to the log file. For Windows-NT number
// of locked pages by default should not be greater then 30.
// If larger number of pages is specified, POST++ will try to extend
// process working set.
//
storage(const char* name,
size_t max_file_size = defaultMaxDatabaseSize,
size_t max_locked_pages = 30)
: data_file(name, max_file_size, max_locked_pages)
{
static_data = false;
}
virtual~storage();
protected:
file data_file;
storage_header* hdr;
storage_free_block* curr_free_page;
long shift;
storage* next;
static storage* chain; // chain of opened storages
class_descriptor** dbs_class_mapping;
int* app_class_mapping;
simple_mutex mutex;
static simple_mutex global_mutex;
enum {
page_size = 512, // bytes
init_page_map_size = 8 // pages
};
bool static_data;
int static_data_index;
static const int block_size[page_size/16];
static const int block_chain[page_size/16];
void* alloc_page(int cid, size_t size);
void free_page(object_header* hp);
virtual void adjust_references(long shift);
virtual int garbage_collection(long shift);
virtual void load_class_dictionary();
virtual bool update_class_dictionary();
void* _allocate(int app_class_id, size_t size) {
int cid = app_class_mapping[app_class_id];
assert(cid != 0);
if (size + sizeof(object_header) <= page_size/2) {
int n = block_chain[((size + sizeof(object_header) + 7) >> 3) - 1];
storage_free_block* bp = hdr->free_block_chain[n];
if (bp != NULL) {
hdr->free_block_chain[n] = bp->next;
bp->size = size;
bp->cid = cid;
return (object_header*)bp+1;
}
}
return alloc_page(cid, size);
}
void call_constructor(object_header* hp);
};
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -