📄 perst.html
字号:
<HTML><HEAD><TITLE>PERST - Simple, Fast, Convenient Object Oriented Database</TITLE><UL><LI> <A HREF = "#introduction">Introduction</A><LI> <A HREF = "#features">Features</A> <UL> <LI> <A HREF = "#pbs">Persistency by reachability</A> <LI> <A HREF = "#load">Semitransparent object loading</A> <LI> <A HREF = "#scheme">Automatic sheme evaluation</A> <LI> <A HREF = "#relations">Relations</A> <LI> <A HREF = "#indices">Indices</A> <LI> <A HREF = "#projection">Projection</A> <LI> <A HREF = "#transaction">Transaction model</A> <LI> <A HREF = "#replication">Replication</A> </UL><LI> <A HREF = "#jsql">JSQL</A> <UL> <LI> <A HREF = "#overview">Overview</A> <LI> <A HREF = "#bnf">JSQL formal grammar</A> <LI> <A HREF = "#array">Arrays</A> <LI> <A HREF = "#string">Strings</A> <LI> <A HREF = "#reference">References</A> <LI> <A HREF = "#function">Functions</A> <LI> <A HREF = "#optimization">Optimization</A> <LI> <A HREF = "#database">Database</A> </UL><LI> <A HREF = "#transparent">Transparent APIs</A> <UL> <LI> <A HREF = "#remoting">Using .Net remoting API</A> <LI> <A HREF = "#props">Using virtual properties</A> </UL><LI> <A HREF = "#implementation">PERST implementation issues</A> <UL> <LI> <A HREF = "#memory">Memory allocation</A> <LI> <A HREF = "#logless">Logless transactions</A> </UL><LI> <A HREF = "#where">Where to use</A><LI> <A HREF = "#quick">Quick start</A><LI> <A HREF = "#tuning">Tuning</A><LI> <A HREF = "#tips">Tricks and tips</A><LI> <A HREF = "WebPages/Solution_Perst.HTM">Perst API Web Pages</A><LI> <A HREF = "../Rdf/doc/manual.html">RDF support</A><LI> <A HREF = "../license.html">Perst license</A></UL></UL><BODY><HR><H2><A NAME = "introduction">Introduction</A></H2>PERST is very simple object oriented embedded database. It is easy to use andprovide high performance. It is intended to be used in applications which needs to deal with persistent data in more sophisticated way than load/store object tree provided but standard serialization mechanism.Although PERST is very simple, it provides fault tolerant support (ACID transactions) and concurrent access to the database.<P> The main advantage of PERST is tight integration with programming language.There is no gap between database and application data models - PERST directly stores language objects.So there is no need in packing/unpacking code, which has to be written for traditional relational databases. Also PERST (unlike many other OODBMS) requires no special compiler or preprocessor. And still it is able to provide high level of transparency.<P><H2> <A NAME = "features">Features</A></H2>Lets now describe key features of PERST architecture. <H3> <A NAME = "pbs">Persistency by reachability</A></H3>PERST is implementing <I>persistency by reachability</I> approach. Object of any class derived from <code>Persistent</code> base class is considered as persistent capable. It is automatically madepersistent and stored in the storage when it is referenced from some other persistent object and<code>store</code> method of that object was invoked. So there is no need (but it is possible) to explicitly assign object to the storage.<P>The storage has one special <I>root</I> object. Root object is the only persistent object accessed in the specialway (using <code>Storage.getRoot</code> method). All other persistent objects are accessed in normal way:either by traversing by references from another persistent objects, either using object containers (<code>Index</code>, <code>Link</code> or <code>Relation</code>). Unlike many other OODBMS, there can be only one root in the storage.If you need to have several named roots, you should create <code>Index</code> object and use it as root object.<P>PERST requires that each persistent capable class should be derived from <code>Persistent</code> class.It makes not possible to store "foreign" classes in the storage. This is the cost of easy use of PERST and lackof any specialized preprocessors or compilers. Also components of persistent capable object are restricted to have the following types:<DL><DT>Scalar types<DD>Any valid CSharp scalar type: boolean, integer, real or enum. For example <code>bool, int, short, double,...</code><DT>String type<DD><code>System.String</code> type<DT>Date type<DD><code>System.DateTime</code> type<DT>Reference to the persistent object<DD>Any class inherited from <code>Persistent</code> or any interface extending <code>IPersistent</code> interface.<DT>Value type<DD>Any C-Sharp value type with the same restrictions for types of components as for persitent capable objects.Values are stored inside the persistent object containing them. <DT>Raw binary type<DD>Any CSharp class not derived from <code>IPersistent</code> or <code>IValue</code> interfaces and marked as Serializable.Standard CSharp serialization mechanism will be used to pack cluster of such objects into byte array which will be stored in the database. The class should be marked with <code>Serializable</code> attributeand should not contain references to persistent objects. <DT>Array type<DD>One dimensional array with type of the components described above<DT>Link type<DD>One-to-many link or from implementation point of view - dynamic array of persistent object.Links are created using <code>Storage.createLink</code> method.</DL><P>Unfortunately it is not possible to detect if object is changed or not without saving old state of the objectand performing field-by-field comparison with new state of the object. But overhead of such solution (both space and CPU) is very high. In PERST it is responsibility of programmer to save object in the storage.It can be done by <code>Persistent.store</code> method. or <code>Persistent.modify</code> methods.<P><code>Persistent.store</code> method writes object in the storage as wellas all objects referenced from this object which are not yet persistent. So if you create tree of objectsand assign reference to the root of this tree to some persistent object <B>X</B>, it is only necessary to invoke <code>store()</code> method in this object <B>X</B>. But then if you update one of the elements in this tree, you should invoke <code>store()</code> individually for each such element (<code>X.store()</code> willNOT now automatically save referenced objects).<P><code>Persistent.modify</code> method mark object is modified but doesn't immediately write it to the storage.All objects marked as modified will be stored to the storage during transaction commit (<code>store</code> methodwill be invoked for each modified object). So using <code>modify</code> method is preferable if objectis updated multiple times within transaction. In this case instead of storing it several times, it willbe stored only once at the end.<P><H3> <A NAME = "load">Semitransparent object loading</A></H3>PERST is not using any special compiler or preprocessor. And since C# doesn't provideruntime behavior reflection (changing behavior of object at runtime), it is not possible to implement completelytransparent persistence (when there are no differences between access to transient and persistent objects).Instead of it PERST propose transparent behavior in most cases with some exceptions.<P><code>IPersistent</code> interface declares <code>recursiveLoading</code> method. Default implementation of this method in <code>Persistent</code> class always returns <code>true</code>. In this case PERST will recursively load any object referenced from target object when target object is loaded. So it cause implicit loading of all cluster of referenced objects from storage to main memory.It is similar with how serialization mechanism works.<P>To avoid overflow of main memory caused by recursive loading of all objects fro the storage, programmer has to overload <code>recursiveLoading</code> method in some classes and return <code>false</code> n it.Objects loaded from such object will not be implicitly loaded and programmer has to explicitly invoke <code>Persistent.load</code> method to load them. So <code>recursiveLoading</code> method can be usedto control loading of objects from storage to main memory.<P>Also it is important to notice that containers (<code>Link, Relation, Index</code>) always load member object on demand (do not perform automatic loading of all objects in the containers). Since access to the container members is always performed through methods of the container class, programmer will never notice it - container methods will alwaysreturn loaded object(s).<P>PERST is using default constructor (constructor without parameters) to create object loaded from the storage. It means the following things:<OL><LI>All persistent capable classes should have default constructor (or have no constructor at all, in this caseit will be automatically generated by compiler). Default constructor should not necessarily be public, it can have anyaccess type. <LI>Default constructor should initialize only transient fields. <LI>Default constructor is used to create instance of the persistent object loaded from the storage. So at the time of default constructor execution field of the constructed object are not yet assigned values stored in the database.If you need these values to be able to perform initialization of transient fields, then you need to perform this initialization in<code>onLoad</code> method which is invoked after fetching of all values of non-transient fields of persistent object from the storage. </OL><P>So summarizing all above, proposed mechanism is convenient and easy to use because it doesn't require programmerto explicitly load any referenced object and from another point of view is is flexible above by providing programmer controlon object loading. Only those classes (usually containers) which explicitly control loading of theirmembers (by overloading <code>recursiveLoading</code> to return <code>false</code> value) should be awarecalling <code>Persistent.load</code> method.<P> <H3> <A NAME = "scheme">Automatic scheme evaluation</A></H3>PERST supports lazy automatic scheme evaluation. When class format is changed, PERST perform conversion of loaded object to new format. If this object is modified, it will be stored in new format. So object is converted to the new format on demand.PERST is able to handle the following scheme changes:<OL><LI>Compatible change of scalar type (change which could not cause data truncation).For example it is possible to change <code>int</code> type to <code>long</code> or <code>int</code> to <code>float</code>. But changing type from <code>int</code> to<code>short</code> is not possible. More precisely, PERST is able to perform any conversionwhich is supported by Java reflection mechanism (field type XXX can be changed to YYYif <code>java.lang.reflect.Field.setXXX</code> method can be applied to the component with type YYY).<LI>Reordering components within class or moving component to base or derived class.<LI>Adding/removing classes from class inheritance hierarchy.<LI>Changing format of classes with value semantic. </OL><P>All other schema modifications (such as renaming fields, incompatible change of field type)could not be handled by PERST automatic schema modification mechanism. In this case you can use Perst XML export/import mechanism. Database can be exported to XML format using <code>Storage.exportXML</code> method, then recreated with new class definitions and after it saved data can be imported using <code>Storage.importXML</code> method.<P><H3> <A NAME = "relations">Relations</A></H3>CSharp references provides a way to implement one-to-one relation between objects.But in many cases one-to-many and many-to-many relations are needed. PERST provides <code>Link</code> interface to deal with relations of such kind.This interface allows to add/delete/inspect members of the relation.Members of the relation can be accessed by index or be extracted as array of objects.<P>Relations can be of two kinds: <I>embedded</I> (when references to the related objects are stored in relationowner object itself) and <I>standalone</I> (when relation is separate object, which containsthe reference to the relation owner and relation members). Both kinds of relationsimplements Link interface. Embedded relation is created by <code>Storage.createLink</code> methodand standalone relation is represented by Relation persistent class created by<code>Storage.createRelation</code> method.<P>So relation between two classes A and B can be implemented in the following way:<P><TABLE BORDER><TR><TH>Relation type</TH><TH>Object A</TH><TH>Object B</TH></TR><TR><TD>one-to-one</TD><TD><code>B bref;</code></TD><TD><code>A aref;</code></TD></TR><TR><TD>one-to-many</TD><TD><code>Link bref;</code></TD><TD><code>A aref;</code></TD></TR><TR><TD>many-to-one</TD><TD><code>B bref;</code></TD><TD><code>Link aref;</code></TD></TR><TR><TD>many-to-many</TD><TD><code>Link bref;</code></TD><TD><code>Link aref;</code></TD></TR></TABLE><P><H3> <A NAME = "indices">Indices</A></H3>Usually objects are accessed by traversing from one object to another using references or links.But it is frequently needed to locate object by key. In .NET <code>Hashtable</code> classcan be used for it. In databases usually more sophisticated search is required. I do not want to implement in PERST complete SQL language, because it immediately makes DBMS huge and slow.But in most cases application is performing only very simple queries using exact match or key range.This is done in PERST by <code>Index</code> and <code>IndexField</code> interfaces. First interface is usedfor independent specification key and associated value. <code>IndexField</code> interface allows to index objectsusing one of the fields of this object (key field).<P>Indices are created in PERST using <code>Storage.createIndex</code> or <code>Storage.createFieldIndex</code> methods. There can be several index implementationsbut right now only one implementation based on B+Tree is provided (because B+Tree is the most efficient structurefor disk based databases). Methods of <code>Index</code> and <code>FieldIndex</code> interface allows to add, remove and locate objects by key. It is possible to perform search either specifying exact key value either specifying range of key values(high or low boundary or both of them can be skipped or can be declared as been exclusive or inclusive).So it is possible to perform the following types of search:<P><OL><LI>key is equals to VAL<LI>key belongs to [MIN_VAL, MAX_VAL]<LI>key belongs to [MIN_VAL, MAX_VAL)<LI>key belongs to (MIN_VAL, MAX_VAL]<LI>key belongs to (MIN_VAL, MAX_VAL)<LI>key is greater than MIN_VAL
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -