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

📄 readme.htm

📁 完全免费的邮件发送程序。delphi 6.0
💻 HTM
📖 第 1 页 / 共 4 页
字号:
\<HTML>
<HEAD>
<TITLE>Persistent Object Storage for C++</TITLE>

<UL>
<LI><A HREF = "#introduction">Introduction</A>
<LI><A HREF = "#classinfo">Describing object class</A>
<LI><A HREF = "#creation">Allocating and deallocating objects in storage</A>
<LI><A HREF = "#object">Persistent object protocol</A>
<LI><A HREF = "#storage::new">Storage constructor</A>
<LI><A HREF = "#storage::open">Opening storage</A>
<LI><A HREF = "#installation">Installation of POST++</A>
<LI><A HREF = "#classes">POST++ class library</A>
<LI><A HREF = "#stl">Using STL classes with POST++</A>
<LI><A HREF = "#new">Replacing of standard allocators</A>
<LI><A HREF = "#usage">How to use POST++</A>
<LI><A HREF = "#debugging">Specific of debugging POST++ applications</A>
<LI><A HREF = "#PS">Some more information about POST++</A>
</UL>

<BODY>
<HR>
<H2><A NAME = "introduction">Introduction</A></H2>

<B>POST++</B> provides simple and effective storage for 
application objects. <B>POST++</B> is based on memory mapping mechanism 
and shadow pages transactions. <B>POST++</B> eliminates any overhead on 
persistent objects access.
Moreover <B>POST++</B> supports work with several storages, 
storing objects with virtual functions, atomic data file update,
provides high performance memory allocator and optional garbage collector for
implicit deallocation of memory. <B>POST++</B> correctly works
with C++ classes using multiple inheritance and pointers inside 
objects.<P> 


<H2><A NAME = "classinfo">Describing object class</A></H2>

POST++ storage manager needs information about persistent object classes
to support garbage collection, relocation of references while loading,
and initialization of pointers to virtual tables. Unfortunately
C++ language provides no facilities to extract information about class
format at runtime. As far as I want to avoid use of some special tools
(preprocessors) or some "dirty trick" solutions (extracting information
about classes from debugging information), this information should
be provided to storage manager by programmer. Such class registration
can be done very easy using special macros provided by POST++.<P>

POST++ uses default constructors for initializing object while loading
from storage. The programmer should include macro 
<CODE>CLASSINFO(NAME, FIELD_LIST)</CODE> in definition of any class, which
instances can be saved in the storage. <CODE>NAME</CODE> corresponds to the 
name of this class. <CODE>FIELD_LIST</CODE> describes reference fields of this 
class. There are three macros defined in file 
<A HREF = "classinfo.h">classinfo.h</A> for describing references:

<DL>
<DT><CODE>REF(x)</CODE><DD>
Describes single reference field.
<DT><CODE>REFS(x)</CODE><DD>
Describes one-dimensional fixed array of references. 
(i.e. array with constant boundaries).
<DT><CODE>VREFS(x)</CODE><DD>
Describes varying one-dimensional array of references. Varying array can be
only the last component in class. When you are writing class declaration, you
specify array with only one element. The actual number of elements in concrete
object instance is specified at object creation time. 
</DL><P>

List of these macros should be separates by spaces: 
<CODE>REF(a) REF(b) REFS(c)</CODE>. 
Macro <CODE>CLASSINFO</CODE> defines default constructor (constructor without
parameters) and declares class descriptor of this class. Class descriptor
is static component of the class with name <CODE>self_class</CODE>. 
So class descriptor of the class <CODE>foo</CODE> can be accessed by
<CODE>foo::self_class</CODE>. As far as constructors without arguments
are called for base classes and components automatically by compiler,
you should not worry about calling them explicitly. But do not forget
to include <CLASS>CLASSINFO</CLASS> macro in definition of any structure,
which can be used as component of serialized class. Then you should
register your class to be accessible by storage manager. 
It can be done by macro <CODE>REGISTER(NAME)</CODE>. Class names
are placed in the storage together with objects. Mapping between application
and storage classes is established during storage opening. Names of all classes
stored in the storage are compared with names of application classes.
If some class name is not found within application classes or 
correspondent application and storage classes have different size, then 
program assertion will fail.<P>


These rules are illustrated by the following example:

<PRE>
struct branch { 
    object* obj;
    int key;

    CLASSINFO(branch, REF(obj));
};

class foo : public object { 
  protected:
    foo*    next;
    foo*    prev;
    object* arr[10];
    branch  branches[8];
    int     x;
    int     y;
    object* childs[1];
  public:
    CLASSINFO(foo, REF(next) REF(prev) REFS(arr) VREFS(linked));
    foo(int x, int y);
};


REGISTER(1, foo);

main() { 
    storage my_storage("foo.odb");
    if (my_storage.open()) { 
        my_root_class* root = (my_root_class*)my_storage.get_root_object();
	if (root == NULL) { 
	    root = new_in(my_storage, my_root)("some parameters for root");
	}
	...
        int n_childs = ...;
	size_t varying_size = (n_childs-1)*sizeof(object*);
	// We should subtract 1 from n_childs, because one element is already
	// present in fixed part of class.
        foo* fp = new (foo:self_class, my_storage, varying_size) foo(x, y);
	...
	my_storage.close();
    }	
}
</PRE><P>

<H2><A NAME = "creation">Allocating and deallocating objects in storage</A></H2>

POST++ provides special memory allocator for managing storage memory.
This allocator uses two different approaches: for allocating small and
large objects. All storage memory is divided into pages (which size 
is independent from operating system page size and in current implementation
of POST++ is 512 bytes). Small objects are those objects, which
size is less or equal to 256 bytes (page size/2). These objects are allocated
using fixed block chains. Each chain contains the list of blocks with the 
same size. Sizes of allocated objects are aligned at 8-byte
boundary. The optimal number of fixed block chains for objects with size not 
greater than 256 is 14 (number of different equipartitions of the page).
Before each object POST++ allocates object header, which contains
class identifier of the object and object size. As far as size of header is
exactly 8 bytes and in C++ size of object is always greater than 0, 
block chain with size 8 can be eliminated. 
Allocation and deallocation of small object usually is very fast: 
it requires only one remove/insert operation from L1 list. 
If the chain is empty and we are attempting to allocate
new object, then new page is allocated and used for storing objects of this 
size (page is divided into the blocks, which are appended to the chain).
Space for large object (with size greater than 256 bytes) is allocated
from free page list. Size of large objects is aligned on page boundary.
POST++ uses first feed, random position algorithm for maintaining list
of free pages (all free segments of pages are sorted by their address and
special pointer is used to follow current position in this list).
Implementation of memory manager can be found in file
<A HREF = "storage.cxx">storage.cxx</A><P>

It is up to the programmer whether to use explicit or implicit memory 
deallocation. Explicit memory deallocation is faster 
(especially for small objects) but implicit deallocation (garbage collection) 
is more reliable. In POST++ mark and sweep garbage collection scheme is used.
There is special object in the storage: <EMP>root object</EMP>. 
Garbage collector first marks all objects accessible from the root object
(i.e. it is possible to reach the object starting from the root object, and
navigating through references). Then all objects that are not marked
during first stage of GC will be deallocated.
Garbage collection can be made during loading objects from the file
(if you pass <CODE>do_garbage_collection</CODE> attribute to 
<CODE>storage::open()</CODE> method). It is also possible to explicitly
invoke garbage collection during program execution by calling 
<CODE>storage::do_mark_and_sweep()</CODE> method. But be sure that there are
no program variable pointed to objects inaccessible from the root objects 
(these objects will be deallocated by GC).<P>

Because of multiple inheritance C++ classes can have non zero offset
within object and references inside object are possible. That is why
we have to use special techniques to access object header. 
POST++ maintains page allocation bitmap each bit of which corresponds to
the page in the storage. If some large object is allocated
at several pages, then bits corresponding to all pages occupied by this object
except first one will be set to 1. All other pages have correspondent bits in 
bitmap cleared.  To find start address of the object, we first align pointer 
value on the page size. Then POST++ finds page in bitmap that contains 
beginning of the object (this page should have zero bit in bitmap). 
Then we extract information about the object size from object header placed 
at the beginning of this page. If size is greater than half of page size then 
we have already found object descriptor: it is at the beginning of the page. 
Otherwise we calculate fixed block size used for this page and round down 
offset of pointer within this page to block size. This scheme of
header location is used by garbage collector, <CODE>operator delete</CODE>
defined in <CODE>object</CODE> class and by methods extracting information
from the object header about object size and class.<P>

In POST++ special overloaded <CODE>new</CODE> method is provided
for allocation of objects in the storage. This method takes as extra 
parameters class descriptor of created object, storage in which object
should be created and, optionally, size of varying part of the object instance.
Macro <CODE>new_in(STORAGE, CLASS)</CODE> provides 
"syntax sugar" for persistent object creation. 
Persistent object can be delete by redefined <CODE>operator delete</CODE>. 


<H2><A NAME = "object">Persistent object protocol</A></H2>

All classes of persistent objects in POST++ should be derived from
<CODE>object</CODE> class defined in <A HREF = "object.h">object.h</A>. 
This class contains no variables and provides methods for object 
allocation/deallocation and obtaining
information about object class and size at runtime. It is possible to 
use <CODE>object</CODE> class as one of multiple bases of inheritance
(order of bases is not significant). Each persistent class should
have constructor which is used by POST++ system (see section 
<A HREF="#classinfo">Describing object class</A>).
That means that you should not use constructor without parameters for
normal object initialization. If your class constructor even has no
meaningful parameters, you should add dummy one to distinguish your
constructor with constructor created by macro <CODE>CLASSINFO</CODE>.<P>

To access objects in persistent storage programmer needs some kind of root
object from which each other object in storage can be accessed by normal 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -