<?xml version="1.0" encoding="UTF-8"?>

<!--
  - Licensed to the Apache Software Foundation (ASF) under one or more
  - contributor license agreements.  See the NOTICE file distributed with
  - this work for additional information regarding copyright ownership.
  - The ASF licenses this file to You under the Apache License, Version 2.0
  - (the "License"); you may not use this file except in compliance with
  - the License.  You may obtain a copy of the License at
  -
  -     http://www.apache.org/licenses/LICENSE-2.0
  -
  - Unless required by applicable law or agreed to in writing, software
  - distributed under the License is distributed on an "AS IS" BASIS,
  - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  - See the License for the specific language governing permissions and
  - limitations under the License.
  -
  - $Id$
  -->

<!DOCTYPE document PUBLIC "-//APACHE//DTD Documentation V1.1//EN" "document-v11.dtd">

<!--
  - Version: $Revision$ $Date$
  -->

<document>
    <header>
        <title>Xindice 1.1 Internals Guide</title>
        <version>$Revision$</version>
        <authors>
            <person id="jb" name="James Bates" email="james@amplexor.com"/>
            <person id="kao" name="Kevin O'Neill" email="kevin@rocketred.com.au"/>
        </authors>
        <notice/>
        <abstract>
            This document describes the internal organization and operation
            of the Xindice native XML database engine. It is important reading
            for those who intend to contribute to Xindice's core engine.
        </abstract>
    </header>
    <body>
        <warning>This documentation is a work in progress and is only applicable to the CVS version of Xindice.
                 Its content is based mainly on close inspection of existing source code and some
                 reverse engeneering. Some of the information may be inaccurate, or at least misleading
                 with respect to the intent of the original core developers (which isn't always obvious
                 from the source code). You have been warned.
        </warning>
        <section>
            <title>1. Overall Xindice architecture</title>
            <p>Xindice is a native XML database engine that is written
               entirely in <em>Java</em>. As such it must always be hosted
               by a <em>Java Virtual Machine</em> (JVM).</p>
            <p>When running, a Xindice instance stores a number of data items in
               Java objects inside the JVM, the most important of which are:</p>
            <ul>
                <li>Object representation of Collection hierarchy</li>
                <li>Client connection sate information</li>
                <li>Various cached data items</li>
            </ul>
            <p>In addition, Xindice needs access to disk files containing the XML
               data, and related meta-data. The files are stored inside a diskfile
               directory hierarchy, that starts somewhere called the <em>database root</em>.
            </p>
            <section>
                <title>1.1. Access modes</title>
                <p>Xindice can be set up to run in a JVM in two different ways,
                   depending on how clients will want to use Xindice.</p>
                <p>In <em>embedded</em> mode, a complete Java application will
                   set up a Xindice instance in <em>its own</em> JVM. Only that one
                   Java application is able to access and manipulate the data in
                   Xindice. Clients using the XML:DB API will use something called the
                   <em>embedded driver</em> to access the Xindice instance that is running
                   inside the same JVM as the host application.</p>
                <p>In <em>server</em> mode, Xindice is run as a standard J2EE <em>web application</em>,
                   in some <em>web application container</em>, such as <link
                   href="http://jakarta.apache.org/tomcat">Apache Tomcat</link>. In this
                   mode, the JVM hosting Xindice, is in fact the JVM running the web application
                   container. Clients connect to Xindice from different JVM's possibly located
                   on different machines, using <em>XML-RPC</em>, a <em>Remote Procedure Call</em>
                   standard designed to work on top of <em>HTTP</em> (which is why Xindice is
                   packaged as a <em>web application</em> in this mode).</p>
            </section>
        </section>
        <section>
            <title>2. Organization of Collections</title>
            <p>Logically, all XML data stored in Xindice is organized into a hierarchy
               of <em>collections</em>. A collection is exactly what its name suggests:
               it contains any number of XML documents, and can in addition contain its
               own child collections, thus providing a hierarchy.</p>
            <p>The &quot;root&quot; collection is also called the <em>Database</em>. It is
               special in that:</p>
            <ol>
                <li>It has no parent.</li>
                <li>It can contain no XML documents of its own. It only has child collections.</li>
            </ol>
            <p>Each collection in the database is represented in Java by an object of class
               <code>org.apache.xindice.core.Collection</code>. As with many Java objects inside
               Xindice, it is initialized using an <em>XML configuration description</em>,
               a piece of XML describing the properties of the collection. This XML configuration
               is modelled in Java as an object of class
               <code>org.apache.xindice.util.Configuration</code>. To set up the configuration of
               a collection, Xindice calls the collection's <code>setConfig()</code> method, passing it
               an appropriately obtained <code>org.apache.xindice.util.Configuration</code> object.</p>
            <section>
                <title>2.1. The Database</title>
                <p>The database, or &quot;root&quot; collection is the Java object
                   that provides the link to everything else used by the Xindice instance.
                   When Xindice first starts, its first act is to create and initialize an
                   object of class <code>org.apache.xindice.core.Database</code>, which extends
                   <code>org.apache.xindice.core.Collection</code>.</p>
                <p>The database object is initialized using an XML configuration file that is obtained
                   from outside the database (i.e. it is stored simply as a file somewhere). In
                   the case of an embedded Xindice instance, the file is referenced using the
                   Java property <code>xindice.configuration</code>, whereas in server mode, the file is
                   referenced by the parameter <code>xindice-configuration</code> in the Xindice web
                   application's <code>web.xml</code> file.</p>
                <p>The format of the XML configuration file used to initialize the database object
                   is as follows:</p>
                <source><![CDATA[
<xindice>
   <root-collection dbroot="./db/" name="db">
      <queryengine>
         <resolver autoindex="false" class="org.apache.xindice.core.query.XPathQueryResolver" />
         <resolver class="org.apache.xindice.core.xupdate.XUpdateQueryResolver" />
      </queryengine>
   </root-collection>
</xindice>
]]></source>
                <p>In fact, if during initialization, the XML configuration file cannot be
                   found for some reason, rather that throw an error, Xindice will <em>assume</em>
                   a default configuration file, which is exactly the one shown above.</p>
                <p>The important elements in this configuration file are:</p>
                <ul>
                    <li>the <code>dbroot</code> attribute of the <code>root-collection</code>
                        element. It is a directory path that can be absolute or relative. If absolute,
                        Xindice will use it right away, if relative,
                        Xindice will try to find a system property called <code>xindice.db.home</code> and
                        append to it the value of the "dbroot" attribute. If such system property
                        is not set, Xindice will try to use the <code>/WEB-INF</code> webapp directory (under
                        Tomcat it will be something like <code>[TOMCAT_HOME]/webapps/xindice/WEB-INF</code>
                        as the parent (be aware that in case of a webapp upgrade it's possible to lose the
                        whole database). If even that fails (e.g. because the WAR file was not unpacked),
                        an Exception will be thrown and Xindice will fail to initialize with a proper
                        log message suggesting a solution.</li>
                    <li>the <code>name</code> attribute of the <code>root-collection</code> element.
                        The root collection (or database) in Xindice is not called simply &quot;/&quot; as
                        you may have expected. It actually has a name; this name is specified here.</li>
                    <li>the various <code>resolver</code> elements in the <code>query-engine</code> element. These
                        point to the <em>query engines</em>, and their Java implementations that this
                        Xindice instance should support. Out of the box, Xindice supports two query styles,
                        <em>XPath</em> and <em>XUpdate</em>. They are detailed in a subsequent chapter.</li>
                </ul>
                <p>Notice that this external configuration file does <em>not</em> specify
                   the <em>child collections</em> of the database. As we will see shortly,
                   these are configured in XML somewhere <em>inside</em> the database,
                   which we can now access (since we know where the database data is
                   stored).</p>
            </section>
            <section>
                <title>2.2. The database root directory</title>
                <p>As indicated, this directory contains all data and meta-data for the
                   XML content of the database.</p>
                <p>The directory structure inside this database root directory reflects
                   the child collection structure of the database. So if there is a child
                   collection named <code>mycol</code> in the database, the database root
                   directory will contain a subdirectory named <code>mycol</code> and so on.</p>
                <p>Each collection's directory contains at the minimum a file with extension
                   <code>.tbl</code> that contains <em>all</em> the XML documents stored in
                   that collection. The file is <em>not</em> human-readable. Its format
                   is explained in subsequent chapters.</p>
            </section>
            <section>
                <title>2.3. The System Collection</title>
                <p>One special collection, called <code>system</code>, always exists within
                   a Xindice database. When the Xindice database is initialized,
                   it automatically also loads the system collection, as this known to always exist.
                   The structure of the system collection is simple: it contains no documents of its
                   own, but contains two child collections: <code>SysConfig</code> and <code>SysSymbols</code>.</p>
                <p>The <code>SysConfig</code> collection contains exactly one document called <code>database.xml</code>.
                   <code>SysSymbols</code> contains various documents that are in fact the <em>Symbol tables</em>
                   used for storage of the element and attribute names of all XML content in the database. The
                   symbol tables are detailed in a subsequent section.</p>
                <p>The <code>database.xml</code> is the XML configuration file that is used to
                   initialize all other collections in the database. It is located in the database itself,
                   because it obviously needs to be updated each time collections are added or removed
                   from the database.</p>
                <p>Its structure is as shown below: (you can check your own configuration by issueing
                   the command-line tool invocation: <code>xindice rd -c /db/system/SysConfig -n database.xml</code>)
                   </p>
                <source><![CDATA[
<database name="db">
    <collections>
        <collection compressed="true" name="james">
            <filer class="org.apache.xindice.core.filer.BTreeFiler" />
            <indexes>
                <index class="org.apache.xindice.core.indexer.ValueIndexer" name="myidx" pattern="sub" />
            </indexes>
            <collections>
                <collection compressed="true" name="sub">
                    <filer class="org.apache.xindice.core.filer.BTreeFiler" />
                    <indexes />
                </collection>
            </collections>
        </collection>
        <collection compressed="true" name="james_sub">
            <filer class="org.apache.xindice.core.filer.BTreeFiler" />
            <indexes />
        </collection>
    </collections>
</database>
                ]]></source>
                <p>As you can plainly see, it is here that the XML configuration for
                   all remaining collections is stored. Please note that the
                   <code>system</code> collection is not mentioned here. The XML configuration
                   for the <code>system</code> is hard-coded into Xindice as follows:</p>
                <source><![CDATA[
<collection name="system">
    <!-- No filer for system collection: it contains no doucments itself -->
    <collections>
        <collection name="SysSymbols" compressed="true">
            <filer class="org.apache.xindice.core.filer.BTreeFiler" />
            <symbols>
                <symbol name="symbols" id="0" />
                <symbol name="symbol" id="1" />
                <symbol name="name" id="2" />
                <symbol name="id" id="3" />
                <symbol name="nsuri" id="4" />
            </symbols>
        </collection>
        <collection name="SysConfig" compressed="false">
            <filer class="org.apache.xindice.core.filer.BTreeFiler" />
        </collection>"
    </collections>"
</collection>
]]></source>
                <p>The only way to modify this configuration is to change
                   the Xindice source code (<code>org.apache.xindice.core.SystemCollection</code>
                   class)and recompile.</p>
            </section>
            <section>
                <title>2.4. Other Collections</title>
                <p>The XML Configuration data used to initialize collection
                   objects in Java (of
                   class <code>org.apache.xindice.core.Collection</code>) is, as shown in
                   the examples above, located in an XML document in the system
                   collection, or, in the case of the system collection itself,
                   hard-coded into Xindice.</p>
                <p>The important aspects of this configuration data are:</p>
                <ul>
                    <li>A collection is represented by a <code>collection</code> configuration
                        element. The <code>name</code> attribute indicates the collection's name.
                        The <code>compressed</code> attribute, usually <code>true</code> indicates
                        how XML data should be encoded by the collection's <em>filer</em>. More
                        on this in a subsequent chapter.</li>
                    <li>Each <code>collection</code> element contains a <code>filer</code> element.
                        This element basically tells the collection the name of a Java class
                        that it can use to read its own <em>data file</em>. (The file with a
                        <code>.tbl</code> extension mentioned earlier).
                        <code>org.apache.xindice.core.filer.BTreeFiler</code> is the most common,
                        and indeed the standard filer class used in Xindice. If a collection has
                        no filer (because the <code>filer</code> element is missing, or because the Java
                        class it points to couldn't be loaded), then it won't be able to store
                        any XML documents. That's the case for example of the database (root collection),
                        and the system collection.</li>
                    <li>A <code>collection</code> element <em>may</em> contain a
                        <code>collections</code> element, which contains one <code>collection</code>
                        element per child collection of the collection under discussion.
                    </li>
                </ul>
            </section>
        </section>
        <section>
            <title>3. Data storage</title>
            <p>The XML data contained in the XML documents of a collection is
               stored in one single data file with extension <code>.tbl</code> that
               is located in the collection's directory somewhere in the database
               root directory. A special Java class called a <em>filer</em> is responsable
               for reading and writing XML data to such a data file.</p>
            <p>In this chapter and the next, we will examine the most common filer in Xindice,
               implemented by the <code>org.apache.xindice.core.filer.BTreeFiler</code> class.
               The mechanism is somewhat complex, but it is broken down into a number
               of superimposed <em>layers</em>, each layer implementing some abstract
               data structure designied to improve overall performance.</p>
            <p>In this chapter, we will concern ourselves not with XML storage directly,
               but the more abstract process of storage of (key,value) pairs. In essence,
               a Xindice file is no more that a performance-oriented format for storing
               (key,value) pairs. We will see later on, that this data format is used not
               only for the storage of XML data itself, but also for the storage of
               <em>indexes.</em></p>
            <p>The <code>org.apache.xindice.core.filer.BTreeFiler</code> class breaks
               up data storage into two layers. The bottom-most layer provides a
               <em>paged file</em> implementation. The code for this layer is located
               in <code>org.apache.core.filer.Paged</code>. On top of the paging layer
               sits a <em>B+-Tree</em> implementation: a balanced tree data structure
               (which allows storage of (key,value) pairs) specially optimized for disk
               access.</p>
            <section>
                <title>3.1. Paged file</title>
                <p>Paging provides efficient access to a random-access file by allowing
                   parts of the file (<em>pages</em>) to be "mapped" to main memory for
                   easy access. Pages have a fixed length. If data that must be stored is
                   longer than the length of one page, subsequent pages in the file can
                   be "linked" to the first.</p>
                <figure src="images/pagedfile.png" alt="Paged file structure"/>
                <p>As shown in the diagram, a paged file consists of a file header, followed by
                   a list of fixed-length pages. The file header is 4kb long, and each page is,
                   by default, 4kb long. (These values can be modified in the
                   <code>org.apache.core.filer.Page</code> source code).</p>
                <p>Each page contains a 64-byte header, followed by actual data. Pages are
                   numbered. Whenever a particular page, say page <code>n</code> is needed, but not yet loaded into
                   memory, the Java code can calculate the start address of the page as:</p>
                   <source>offset = fileHeaderSize + (n * pageSize)</source>
                <p>At this address, it will then find the header of the wanted page, and 64 bytes
                   further, the start of the page's data.</p>
                <section>
                    <title>3.1.1. Paged file header</title>
                    <p>The paged file header consists of a number of fixed-length fields.
                       Fields which are longer than one byte, are <em>always</em> stored in
                       Big Endian format, which means the most significant byte is written at the
                       lowest address. This is regardless of the type of architecture the server
                       process is running on, so your data files are portable between
                       architectures.</p>
                    <figure src="images/pagedfilehdr.png" alt="File header structure"/>
                    <p>The meaning of the various fields in the file header, whose structure
                       is shown above, is as follows:</p>
                    <ul>
                        <li>header size (2 bytes): set to 4096 (0x1000), the size of this header.</li>
                        <li>page size (4 bytes): set to 4096 (0x00001000), the page size.</li>
                        <li>page count (8 bytes): this field is not used consistently. It is
                            present mainly for historical reason.</li>
                        <li>total page count (8 bytes): total number of pages present in this file.</li>
                        <li>first free page (8 bytes): page number of the first unused page in this file. (see below)</li>
                        <li>last free page (8 bytes): page number of the last unused page in this file. (see below)</li>
                        <li>page header size (1 byte): size of each page header. Set to 64 (0x40) by default.</li>
                        <li>max key size (2 bytes): see below.</li>
                        <li>record count (8 bytes): number of <em>records</em> stored in this file. (see below)</li>
                    </ul>
                    <p>Classes, such as the <code>org.apache.xindice.core.filer.BTree</code> class, which extend
                    the paged class can add further fields of their own to this header.</p>
                </section>
                <section>
                    <title>3.1.2. Pages and records</title>
                    <p>As indicated in the introduction, the idea of using a <em>paged</em> file is
                       that data values can be stored that are longer that available page length.
                       A stored data value is called a <em>record</em>. If the length of data in a record
                       fits into the available space in a single page, nothing special happend. But if
                       the record data doesn't fit into a single page, then the first page is filled with
                       the start of the record, and subsequent pages are used to store the remainder. In
                       this situation storage of a record uses several pages, which are linked together
                       with appropriate fields in the header (see next section). Below is an example of
                       a record stored in 4 different pages:</p>
                    <figure src="images/linkedpages.png" alt="Linked pages"/>
                    <p><em>Unused</em> pages which exist in the data file, but are free to be used for
                       data, are all linked together into the <em>unused page list</em>, in the same
                       manner (i.e. using the <code>next page</code> field in page headers) as pages
                       used to store a record. The first page number in this unused page linked list is
                       stored in the file header <code>first free page</code> field, and the last page in
                       the <code>last free page</code> field.</p>
                </section>
                <section>
                    <title>3.1.3. Page header</title>
                    <figure src="images/pagehdr.png" alt="Page header structure"/>
                    <p>Each page has its own header, whose structure is shown above.
                       The meaning of the various fields is as follows:</p>
                    <ul><li>status (1 byte): Pages in the data file are either <em>used</em> or
                            <em>unused</em>. <em>Used</em> pages contain actual data.<br/>
                            When a data value (called <em>record</em> in paging terminology) has to be
                               written to the paged file that is longer than the page size will allow (i.e. longer
                               than the page size - page header size), a new page is allocated for the part of the value
                               that doesn't fit in the first page. The header of the first page's next page field is then
                               set to the page number of this new page. If the data is still too long for both pages,
                               a third one is allocated and pointed to by the second, and so on.<br/>
                            When a page is unused, its status is set to <code>UNUSED</code>, encoded by the
                               value 0x00. If a page is used to store the <em>first</em> part of a record, (or only
                               part if the record is short enough), the status is set to a value that is used by the
                               B-Tree algorithm. If, on the other hand, the page contains the <em>remainder</em> of
                               some record started in some other page, its status is set to <code>OVERFLOW</code>, encoded
                               by the value 0x7E.</li>
                        <li>key length (2 bytes): pages have the possibility of storing a <em>key</em>
                               just before their actual data. The maximum length of such a key is set in the
                               file header's max key size field to 256 (0x0100). The <em>actual size</em> of the
                               key located in this page, if any, is set in this field. Data for this
                               page thus begins <code>64 + (key_length)</code> bytes beyond the start of the page.<br/>
                            If no key is used in this page, this field is 0.</li>
                        <li>key hash (4 bytes): As the name suggests, this field stores a 32-bit hash value calculated
                               from the key. Used to optimize searches mainly.</li>
                        <li>data len (4 bytes): The length of the data stored <em>in this page</em>. If some of the data
                               of the record stored here continues into a subsequent page, this field contains the length
                               of the data stored in <em>this page</em> only.</li>
                        <li>record len (4 bytes): the total length of the data record of which part
                               is stored in this page.</li>
                        <li>next page (8 bytes): page number of the page that contains subsequent
                               data for the record stored in this page, if more data is available.<br/>
                            If this is the last page that stores data for the record, this field contains
                               -1 (0xFFFFFFFF).</li>
                    </ul>
                </section>
            </section>
            <section>
                <title>3.2. The B-Tree storage format</title>
                <section>
                    <title>3.2.1. B-Trees</title>
                    <p>The B-Tree (as used by Xindice) is a data structure that allows for
                       disk-efficient organization of keys. The B-Tree is such that keys can be
                       rapidly retrieved from the tree, allong with associated data.</p>
                    <figure src="images/btree.png" alt="An example BTree"/>
                    <p>A <em>node</em> in a B-Tree consists of a set of values. <em>Between</em> each pair
                       of values in a node is a <em>pointer</em> to a child node. The idea is that when
                       searching for a key, starting from the root node, at each node the sought key is compared
                       to the values in that node, and a path is chosen immediately to the right of the smallest
                       value that is equal to or greater than the sought key. This process continues until
                       a leaf node (which has no pointers to other nodes), in which case the value is present or not.
                       If not present, the value doesn't exist in the tree.</p>
                    <p>Note that searches <em>always</em> terminate on a leaf node. This means that
                       we can determine which keys are present in the B-Tree simply by looking at all
                       the leaf nodes. This is not the case of all B-Trees, but Xindice B-Trees are
                       always organized this way.</p>
                    <p>For a given tree, there is a maximum and minimum number of values that should be present in
                       each non-leaf node. The desired number of values is trade-off between the number of steps required
                       by the search algorithm, and the size of each node (which is read entirely into memory at the
                       appropriate step). In the example shown above, the maxium chosen was 4, and the minimum 2.</p>
                    <p>When inserting and deleting values from the tree, some complicated operations may be necessary,
                       such as <em>splitting</em> and <em>collapsing</em> non-leaf nodes. The manner in which these
                       are done greatly influences the performance of updates to B-Tree files.</p>
                    <p>Any good database book should provide a much more detailed explanation of the theory
                       behind B-Trees than this short introduction paragraph.</p>
                </section>
                <section>
                    <title>3.2.2. Storing B-Trees in a paged file</title>
                    <p>Xindice implements B-Trees using the paged file, described in a previous section.
                       Each node in the B-Tree is stored in a record, spanning one or more pages.</p>
                    <p>In addition to the nodes of the B-Tree, Xindice's B-Tree filer also stores
                       <em>data</em> that is associated with some key. This data is stored in separate
                       records (also spanning one or more pages). Leaf nodes in the B-Tree (recall that
                       the set of all leaf-nodes in the tree contains <em>all</em> keys used) contain pointers
                       to the records that contain the data associated with the keys (in the leaf nodes).</p>
                    <p>The B-Tree filer (implemented by both <code>org.apache.xindice.core.filer.BTree</code> and
                       <code>org.apache.xindice.core.filer.BTreeFiler</code>) thus deals with three kinds of records
                       in the paged file that it manages:</p>
                    <ul><li>non-leaf nodes, called <em>branch</em> nodes of the B-Tree. Such nodes
                            contain a list of key values interwoven with pointers to other B-Tree
                            nodes.</li>
                        <li>leaf nodes of the B-Tree. Such nodes contain a list of key values, and associated with each
                            a pointer to a data record, which contains the data associated with the key.</li>
                        <li>data records. These records are not part of the B-Tree, but the leaf nodes
                            in the tree <em>point</em> to them.</li>
                    </ul>
                    <p>The B-Tree implementation adds some extra fields to both the paged file header
                       and page headers for its internal organization. The details are as follows:</p>
                    <section>
                        <title>3.2.2.1. B-Tree filer paged file header</title>
                        <figure src="images/btreefilerheader.png" alt="The B-Tree filer paged file header"/>
                        <p>The two extra fields (in Big Endian byte order, as usual) are:</p>
                        <ul>
                            <li><code>root node page number</code> (8 bytes): The page number of the
                                page where the record that holds the root node of the B-Tree starts.</li>
                            <li><code>total bytes</code> (8 bytes): the size, in bytes of the file holding
                                the B-Tree node- and data-records.</li>
                        </ul>
                    </section>
                    <section>
                        <title>3.2.2.2. B-Tree filer page header</title>
                        <figure src="images/btreefilerpageheader.png" alt="The B-Tree filer page header"/>
                        <p>The extra fields (in Big Endian byte order, as usual) are:</p>
                        <ul>
                            <li><code>status</code> (1 byte): Some extra values are possible here, above those
                                used in the standard page file. The field is used in the first page
                                of a record to indicate which of the three kinds of record it is:
                                <ul>
                                    <li>a record used to store a branch node of a B-Tree will have
                                        status <code>0x01</code>.</li>
                                    <li>a record used to store a leaf node of a B-Tree will have
                                        status <code>0x02</code>.</li>
                                    <li>a record used to store data will have status <code>0x14</code>.</li>
                                </ul></li>
                            <li><code>val_count</code> (2 bytes): If the record is used to store
                                a node of the B-Tree, then this field indicates how many (key) values there are in
                                the node.</li>
                            <li><code>created</code> (8 bytes): If the record is used to store data, then the time
                                (in UNIX long format) when the data record was created is stored here.</li>
                            <li><code>modified</code> (8 bytes): If the record is used to store data, then the time
                                (in UNIX long format) when the data record was last modified is stored here.</li>
                        </ul>
                    </section>
                </section>
                <section>
                    <title>3.2.3. B-Tree node storage</title>
                    <p>The last remaining question is: how is a B-Tree node stored in its record in
                       the paged file? Recall that a B-Tree node contains a certain number of key values,
                       and an associated set of pointers (in fact page numbers of the start of related records).</p>
                    <p>In the case of branch nodes, there is one more pointer than there are values; the pointers point
                       to other nodes in the B-Tree. In the case of leaf nodes, there are exactly as many pointers as
                       key values, and each pointer points to the data record associated with one of the key values.</p>
                    <p>In either case, the node is encoded as follows:</p>
                    <ul><li>For each key value, two fields are written. Keys in the Xindice implementation
                            are not numbers, as in the image of a B-Tree above, but rather strings of character
                            data. For each of these strings, Xindice encodes the string in utf-8, resulting
                            in a byte array, and writes:
                            <ul>
                                <li>The length of the resulting utf-8 byte array. This length is written over
                                    two bytes.</li>
                                <li>The bytes representing the key value (a string), in utf-8.</li>
                            </ul>
                            The number of values present is known from the page header.
                        </li>
                        <li>Immediately following the key data come the pointers. These are written simply one
                            after the other, each occupying 8 bytes. (Each pointer is the page number of the
                            first page holding the record being pointed to). The number of pointers is known
                            from the number of key values, and whether the node is a leaf- or branch node.</li>
                    </ul>

                </section>
            </section>
        </section>
        <section>
            <title>4. XML storage</title>
            <p>As we saw in the preceding chapter, the B-Tree file format allows for the
               efficient storage of (key, value) pairs. In this chapter we concern ourselves
               with using such a (key, value) storage facility to store the XML content of all
               XML documents in a collection.</p>
            <p>The principle Xindice uses is deceptively simple here: for every XML <em>document</em>,
               Xindice will calculate something called the <em>compressed DOM</em>. This is an array of bytes
               which can be used to reconstruct the complete XML document at any time. An XML document is
               then stored as a (key, value) pair in the B-Tree, where the key is the name given to the XML document,
               and the value is the calculated Compressed DOM.</p>
            <p>The remaining mechanism to investigate is thus how to construct the Compressed DOM
               of a document.</p>
            <section>
                <title>4.1. The symbol tables</title>
                <p>In order to store the XML content in a space-efficient manner, Xindice uses
                   something called a <em>Symbol table</em>. This is an XML file which associates
                   a 16-bit number with any (QName,namespace URI) pair used as element or attribute name
                   in XML <em>all</em> XML files stored in a collection. (i.e. there is <em>one</em>
                   symbol table per collection).</p>
                <p>Consider the following XML document, to be added to a Xindice collection:</p>
<source><![CDATA[
<?xml version="1.0"?>
<p:person xmlns:p="http://www.xindice.org/Examples/PersonData"
          gender="female"
          xml:lang="fr">
    <p:first-name>Susanne</p:first-name>
    <p:last-name>Carpentier</p:last-name>
    <p:e-mail active="yes">scarpentier23@freenet.fr</p:e-mail>
</p:person>
]]></source>
                <p>When this document is stored into an empty Xindice collection, the following
                   symbol table is created:</p>
<source><![CDATA[
<?xml version="1.0"?>
<?xindice-class org.apache.xindice.xml.SymbolTable?>
<symbols>
    <symbol name="p:first-name" nsuri="http://www.xindice.org/Examples/PersonData" id="4" />
    <symbol name="p:e-mail" nsuri="http://www.xindice.org/Examples/PersonData" id="6" />
    <symbol name="p:last-name" nsuri="http://www.xindice.org/Examples/PersonData" id="5" />
    <symbol name="gender" id="2" />
    <symbol name="xml:lang" id="3" />
    <symbol name="p:person" nsuri="http://www.xindice.org/Examples/PersonData" id="0" />
    <symbol name="active" id="7" />
    <symbol name="xmlns:p" nsuri="http://www.w3.org/2000/xmlns/" id="1" />
</symbols>
]]></source>
                <p>As you can see, the symbol table is itself an XML document which contains
                   an element for every (QName, namespace URI) pair used in element and attribute
                   names in the XML documents of the collection. The <code>id</code> attribute is
                   the 16-bit number that Xindice has assigned to the (QName, namespace URI) pair.</p>
                <p>As more documents are added to the
                   collection using different element and attribute names, entries are added to the
                   collection's symbol table.</p>
                <p>Usually, a collections's symbol table is stored as any other XML document in
                   the Xindice database. All symbol tables stored in Xindice are in the
                   <code>system/SysSymbols</code> collection using as name the path of the collection,
                   with underscores (_) subsituted for the /'s in the collection path.</p>
                <p>Being a collection in Xindice, <code>system/SysSymbols</code> itself has
                   a symbol table too. It is:</p>
<source><![CDATA[
<symbols>
    <symbol name="symbols" id="0" />
    <symbol name="symbol" id="1" />
    <symbol name="name" id="2" />
    <symbol name="id" id="3" />
    <symbol name="nsuri" id="4" />
</symbols>
]]></source>
                <p>Normally, this symbol table should be stored in an XML document named
                   <code>system_SysSymbols</code> in the <code>system/SysSymbols</code>
                   collection. Doing so however would create an endless loop, as
                   <code>system/SysSymbols</code>'s symbol table is needed to read itself!
                   This particular symbol table is therefore hardcoded
                   (<code>org.apache.xindice.core.SystemCollection</code> class) into the Xindice
                   source code.</p>
                <p>For any other collection, you can always request the symbol table
                   yourself by issuing the Xindice command-line invocation:</p>
<source>xindice rd -c /db/system/SysSymbols -n [your_collection_path]</source>
            </section>
            <section>
                <title>4.2. The Compressed DOM</title>
                <p>Now that we understand symbol tables, we can take a look at the way in
                   which Xindice generated a byte string from any given XML document.</p>
                <p>The trick is to understand that Xindice simply runs through the XML document
                   recursively, building a byte sequence for a particular node in the tree
                   representation of the XML. This will contain the byte data for the children
                   of the node, and these sub-sequences contain the data for their children etc...</p>
                <p>Xindice thus starts by generating the byte sequence for the document node, which
                   will set off generation for the whole XML document. The code that handles this
                   is located in the <code>org.apache.xindice.xml.dom.DOMCompressor</code> class.</p>
                <section>
                    <title>4.2.1. Document node</title>
                    <p>The document node, which can at most contain some processing intructions,
                       comments, and exactly one element, is encoded as follows:</p>
                    <figure src="images/document.png" alt="Document node compressed DOM format"/>
                    <p>The 4-byte <code>record_length</code> field, which is always encoded in Big Endian order,
                       i.e. the most significant byte at the lowest address, indicates the total length,
                       in bytes, of the encoded document byte array, <em>excluding</em> the 4 bytes
                       used by <code>record_length</code>.</p>
                    <p>The child data is formed by concatenating the byte arrays generated by the processing
                       instruction, comment and element nodes inside the document, in the order they appear
                       in the document.</p>
                </section>
                <section>
                    <title>4.2.2. Element nodes</title>
                    <p>An element node is encoded as shown in the diagram below:</p>
                    <figure src="images/element.png" alt="Element compressed DOM format"/>
                    <p>All multibyte fields are always encoded in Big Endian order, i.e. the
                       most significant byte is at the lowest address.
                       The meaning of the various fields is as follows:</p>
                    <ul>
                        <li>The signature (1 byte) is composed of several 1- or 2-bit fields whose
                            meaning is:
                            <ul>
                                <li>
                                    <code>Attribute Count Type</code> (bits 0-1). This is a code
                                    that indicates the length of the <code>attribute_count</code> field. The
                                    code works as follows:
                                    <ul>
                                        <li>value <code>00</code> (binary): the <code>attribute_count</code> field is zero, and
                                            thus <em>absent</em> from the byte array</li>
                                        <li>value <code>01</code> (binary): the <code>attribute_count</code> field is
                                            4 bytes (32 bits) long.</li>
                                        <li>value <code>10</code> (binary): the <code>attribute_count</code> field is
                                            2 bytes (16 bits) long.</li>
                                        <li>value <code>11</code> (binary): the <code>attribute_count</code> field is
                                            1 byte (8 bits) long.</li>
                                    </ul>
                                </li>
                                <li>
                                    <code>Record Length Type</code> (bits 2-3). This is a code
                                    that indicates the length of the <code>record_length</code> field. The
                                    code works exactly as the <code>Attribute Count Type</code> code above, except
                                    it cannot be <code>00</code>, as the <code>record_length</code> field is never zero.
                                </li>
                                <li>
                                    <code>C</code> (bit 4). Tells whether the element has any non-attribute children
                                    (child elements, text or comments). <code>0</code> means it hasn't, <code>1</code>
                                    means it has.
                                </li>
                                <li>
                                    <code>A</code> (bit 5). Tells whether the element has any attributes.
                                    <code>0</code> means it hasn't, <code>1</code> means it has.
                                </li>
                                <li>
                                    signature type (bits 6-7). Always set to <code>01</code> for elements.
                                    It tells Xindice that what follows is an element signature.
                                </li>
                            </ul>
                        </li>
                        <li><code>record_length</code> (<code>x</code>: number of
                            bytes inidicated by <code>RLT</code> code in signature): the length, in bytes, of the byte string
                            representing this signature. That is including the signature byte, this <code>record_length</code>
                            field, the <code>symbol_id</code> field and any child &amp; attribute data.
                        </li>
                        <li><code>symbol_id</code> (2 bytes): This is the 16-bit identifier that is associated with the
                            element <em>name</em> (QName and namespace URI) of this element in the containing collection's symbol table.
                        </li>
                        <li><code>attribute_count</code> (<code>y</code>: number of
                            bytes indicated by <code>ACT</code> code in signature): the number of attributes
                            this element has. This allows Xindice to start reading the child &amp; attribute data, knowing
                            that the first <code>attribute_count</code> nodes will represent attributes.
                        </li>
                        <li>child &amp; attribute data: Attribute data is written first; it is obtained by generating
                            byte arrays for all attribute nodes in this element and concatenating them together. Immediately
                            following the attribute data come the byte sequences obtained by compressing the comment, text
                            and child element nodes of this element. They are processed in the order they appear in the XML
                            document. Again, the byte sequences thus generated by child nodes are concenated together.
                        </li>
                    </ul>

                </section>
                <section>
                    <title>4.2.3. Attribute nodes</title>
                    <p>An attribute node is encoded as follows:</p>
                    <figure src="images/attribute.png" alt="Attribute compressed DOM format"/>
                    <p>Once again, both 2-byte fields are Big Endian.</p>
                    <ul>
                        <li>The <code>symbol_id</code> (2 bytes) is the identifier that is associated with the
                            attribute <em>name</em> (QName and namespace URI) of this attribute in the
                            containing collection's symbol table.
                        </li>
                        <li>The <code>length</code> (2 bytes) is the length, in bytes of the <code>data</code> field
                            that follows. Note the length of <code>length</code> is fixed at 2 bytes, so an
                            attribute's data can be at most 65536 bytes long.
                        </li>
                        <li>The <code>data</code> is the byte array obtained by encoding the character data that
                            is the attribute value in UTF-8. Note that the number of bytes will in general be more
                            than the number of characers encoded by them, as UTF-8 is a variable character-width
                            encoding scheme.
                        </li>
                    </ul>
                </section>
                <section>
                    <title>4.2.4. Text nodes</title>
                    <p>A text node is encoded as follows:</p>
                    <figure src="images/text.png" alt="Text node compressed DOM format"/>
                    <p>The meaning of the various fields is as follows:</p>
                    <ul>
                        <li><code>signature</code> (1 byte): is composed of several bit fields
                            as follows:
                            <ul>
                                <li>bits 0-1: unused, and always set to <code>00</code></li>
                                <li>Record Length Type (bits 2-3): used to indicate
                                    the length of the <code>rec_length</code> field exactly
                                    as for elements.</li>
                                <li>bits 4-5: unused, and always set to <code>00</code></li>
                                <li>signature type (bits 6-7): for text nodes, these are
                                    set to <code>00</code>. These allow Xindice to know that the
                                    encoded node is a text node.</li>
                            </ul>
                        </li>
                        <li><code>record_length</code> (x: as indicated in <code>RTL</code>): length
                            of the complete byte array for this text node, <em>including</em> the signature
                            and this <code>record_length</code> field. As this field could be 4 bytes long,
                            there is not the same restriction on text node length as there is on attribute
                            length.</li>
                        <li><code>data</code>: This is the byte array obtained by encoding the character data
                            of the text node in UTF-8.</li>
                    </ul>
                </section>
                <section>
                    <title>4.2.5. Comment nodes</title>
                    <p>A comment node is encoded as follows:</p>
                    <figure src="images/comment.png" alt="Comment node compressed DOM format"/>
                    <p>The meaning of the various fields is as follows:</p>
                    <ul>
                        <li><code>signature</code> (1 byte): fixed at 0xE0 for comments
                        </li>
                        <li><code>record_length</code> (4 bytes): length
                            of the complete byte array for this comment node, <em>including</em> the signature
                            and this <code>record_length</code> field.</li>
                        <li><code>data</code>: This is the byte array obtained by encoding the character data
                            of comment node in UTF-8.</li>
                    </ul>
                </section>
                <section>
                    <title>4.2.6. Processing Instruction nodes</title>
                    <p>Contrary to intuition, procedding instruction nodes are not stored
                       using the sytmbol table for the PI target. In stead a signle text value
                       is constructed by concatenating the PI target, one single space (U+0020)
                       and the PI data. This text is then used to encode the PI node as follows:</p>
                    <figure src="images/pi.png" alt="Processing instruction node compressed DOM format"/>
                    <p>The meaning of the various fields is as follows:</p>
                    <ul>
                        <li><code>signature</code> (1 byte): fixed at 0x80 for PI nodes
                        </li>
                        <li><code>record_length</code> (4 bytes): length
                            of the complete byte array for this pi node, <em>including</em> the signature
                            and this <code>record_length</code> field.</li>
                        <li><code>data</code>: This is the byte array obtained by encoding the concatenated
                            character data calculated earlier, in UTF-8.</li>
                    </ul>
                </section>
            </section>
        </section>
        <section>
            <title>5. Queries</title>
            <p>Queries in Xindice provide functionality for looking up and retrieving
               documents or parts of documents using a variety of query languages. Updates
               of the database itself are also possible using queries.</p>
            <p>The query architecture is quite modular, and so will first inspect it at
               an abstract level before delving into the details of Xindice's two
               native query languages, XPath and XUpdate.</p>
            <section>
                <title>5.1. The Query interfaces</title>
                <p>When Xindice first initializes itself, it creates amongst other things
                   a <em>Query engine</em>, implemented by
                   <code>org.apache.xindice.core.query.QueryEngine</code>. The principal purpose
                   of this query engine is to setup one or more <em>Query resolvers</em>.
                   Query resolvers are Java classes that handle all querying functionality
                   related to one particular query language, e.g. XPath or XUpdate. The
                   source code refers to these as <em>query styles</em>.</p>
                <p>A query resolver is represented by the Java interface
                   <code>org.apache.xindice.core.query.QueryResolver</code>. Two implementations,
                   one for XPath and one for XUpdate of this interface exist within Xindice,
                   but you could add your own implementations to support other query
                   languages. As usual, loading and initializing the appropriate query resolvers is done
                   by parsing a piece of XML configuration data (The <code>query-engine</code>
                   element of the database configuration file).</p>
                <p>The <code>org.apache.xindice.core.query.QueryResolver</code> interface provides
                   two important methods: <code>query()</code> and <code>compileQuery()</code>.
                   Both model a complete invokation of a query <em>on a collection</em>. They
                   accept the following parameters:</p>
                <ul><li><code>org.apache.xindice.core.Collection</code> <strong><code>context</code></strong>: This
                    is the collection in which the query is to be invoked. All results will be
                    fragments of XML from documents in this collection. Cross-collection queries
                    are never possible in Xindice.</li>
                    <li><code>java.lang.String</code> <strong><code>query</code></strong>: This is the query expression
                    to be invoked. The syntax of the expression depends on the query language being
                    implemented by the resolver.</li>
                    <li><code>org.apache.xindice.xml.NamespaceMap</code> <strong><code>nsMap</code></strong>: The query
                    expression will generally contain element names. Both XPath and XUpdate allow
                    using element names in their syntax. Often these element names will be
                    <em>qualified</em> by a namespace prefix, which needs to be <em>resolved</em> by
                    the query resolver in order to find the exact namespace uri being represented.
                    This namespace map allows a query resolver to do just that.</li>
                    <li><code>org.apache.xindice.core.data.Key[]</code> <strong><code>keys</code></strong>: This parameter,
                    if not <code>null</code> provides a set of <em>doccument names</em> (called keys
                    internally) in the collection that should be considered by the query invokation.
                    If the parameter <em>is</em> <code>null</code>, then <em>all</em> documents in the
                    collection are considered.</li>
                </ul>
                <p>The difference between both methods is that <code>query()</code> invokes the query
                   immediately and returns results, whereas <code>compileQuery()</code> encapsulates
                   the invokation into a <code>org.apache.xindice.core.query.Query</code> object which
                   can be used several times later on to invoke the query.</p>
                <p>We now turn our attention to the two provided query resolvers XPath and XUpdate.</p>
            </section>
            <section>
                <title>5.2. XPath Queries</title>
                <p>The <code>org.apache.core.query.XPathQueryResolver</code> class
                   implements a query resolver for the XPath language. Recall that
                   a query resolver provides two query methods: one for immediate execution
                   and another for storing (after compiling) invokations for later use.</p>
                <p>Internally, the xpath query resolver <em>always</em> compiles queries
                   into a <code>org.apache.core.query.XPathQueryResolver.XPathQuery</code>.
                   It then may or may not execute the query immediately depending on which
                   method was called on the resolver.</p>
                <p>Analyzing and compiling the query is actually handled by Xalan, not Xindice.
                   Xalan contains XPath manipulation and evaluation classes, and Xindice uses
                   these.</p>
                <p>When an XPath query needs to be evaluated, a set of candidate documents is
                   selected from the collection. Then the XPath is evaluated using the Xalan
                   classes against each of these documents in turn: the document is loaded into
                   a DOM tree using the compressed DOM and B-Tree filer classes, and the XPath
                   is evaulated against this DOM tree. The results of all evaluations are
                   aggregated and returned.</p>
                <p>It follows from the above that there is absolutely no performance gain in using
                   Xindice to evaluate an XPath with respect to a document. Using a parsed XML file,
                   exactly the same performance would result. Xindice's main contribution is in
                   searching through a large collection of documents, as in this case, it can use
                   indexes to intelligently select a set of candidate documents, as we will now
                   see.</p>
                <section>
                   <title>5.2.1. Selecting candidate documents from a collection</title>
                   <p>When performing a query, recall it is posible to specify which documents
                      should be considered. If this is done, then Xindice will use the provided
                      set as the candidate set, and execute the XPath query against <em>each</em>
                      of them, reading them into memory first.</p>
                   <p>If however no explicit set of documents is speficied, Xindice will try to
                      locate an appropriate index based on the XPath query. This index can then
                      provide an intelligent set of candidate documents, and the
                      XPath is evaluated against only these documents. The details of indexes
                      are explained in the next chapter.</p>
                   <p>If no appropriate index is found, Xindice resorts to "brute force": it
                      evaluates the XPath expression against <em>every</em> document in the
                      collection, thus effectively reading in, parsing and searching each
                      document.</p>
                </section>
            </section>
            <section>
                <title>5.3. XUpdate Queries</title>
                <p>XUpdate queries are used to send update instructions to Xindice. An
                   XUpdate query is actually a complete XML document which can contain
                   any number of update instructions. As it is an XML document of itself,
                   the namespace bindings for prefixes used in the XUpdate instructions
                   can be specified in the XUpdate string itself. They can also be specified
                   as a <code>NamespaceMap</code> when calling a query method on the resolver.
                   This may cause a conflict if the same prefix is bound both in the XUpdate,
                   and in the provided <code>NamespaceMap</code>. By default, Xindice will
                   take into account the value specified in the <code>NamespaceMap</code> in
                   this case, though the behaviour can be altered by modifying the
                   <code>org.apache.xindice.core.xupdate.XUpdateImpl.API_NS_PRECEDENCE</code>
                   constant in the source code and recompiling.</p>
                <p>The <code>org.apache.xindice.core.xupdate.XUpdateQueryResolver</code>
                   class provides a query resolver for XUpdate queries. Just as the
                   XPath resolver, it always first compiles queries to a
                   <code>org.apache.xindice.core.xupdate.XUpdateQueryResolver.XUpdateQuery</code>,
                   wich it then immediately executes if the resolver's <code>query()</code> method
                   was called.</p>
                <p>Xindice uses the Lexus engine, produced at infozone.org to parse and execute
                   XUpdate instructions. The <code>org.apache.xindice.core.xupdate.XUpdateQueryResolver.XUpdateQuery</code>
                   and <code>org.apache.xindice.core.xupdate.XUpdateImpl</code> classes basically
                   provide some glue around Lexus.</p>
                <p>Lexus itself doesn't contain an XPath evaluator, and so Xindice needs
                   to provide one to use Lexus. We saw earlier that Xindice itself uses Xalan
                   for its XPath needs. To provide a valid XPath implementation to Lexus,
                   another class <code>org.apache.xindice.core.xupdate.XPathQueryImpl</code> exists
                   which encapsulates Xalan's XPath classes in a manner suitable for Lexus. Don't
                   confuse this class with <code>org.apache.core.query.XPathQueryResolver.XPathQuery</code>,
                   which also wraps around Xalan, but for use by Xindice's own XPath query
                   resolver.</p>
                <section>
                    <title>5.3.1. Selecting documents to update</title>
                    <p>When an XUpdate query is submitted with a specified set of documents,
                       the all the XUpdate modification instructions are performed on each
                       of the documents.</p>
                    <p>If however no documents are specified, Xindice proceeds as follows:</p>
                    <ul>
                        <li>For each of the modification instructions, it looks up the
                        <em>selector expression</em>, that is an XPath expression that each
                        XUpdate modification instruction contains to indicate <em>which</em>
                        node in a document should be modified.</li>
                        <li>Next, a complete XPath query is performed on the collection, using
                        the <code>org.apache.xindice.core.query.XPathQueryResolver</code> to
                        find all nodes matching the XPath in documents in the collection, and
                        these nodes' containing documents are retained. Note that this step
                        <em>might</em> make use of any indexes set up for XPath, as determined
                        by the behaviour of the XPath query resoolver.</li>
                        <li>The XUpdate modification instruction is performed on the retained
                        set of documents.</li>
                    </ul>
                </section>
                <section>
                    <title>5.3.2. Performing the updates</title>
                    <p>Whether explicitly passed as an argument to the query method, or whether
                       determined by evaluating the selector expression on the collection, the
                       set of documents is always processed as follows:</p>
                    <ul><li>Each document in the set is read in to a DOM tree in memory using
                        the DOM Compressor and B-Tree filer classes.</li>
                        <li>Lexus updates this in-memory DOM representation according to
                            the modification instructions.</li>
                        <li>Xindice writes the <em>entire document</em> back using the
                        same DOM Compressor and B-Tree filer classes. The modification time
                        <em>of the whole document</em> is updated appropriately.</li>
                    </ul>
                </section>
                <section>
                    <title>5.3.3. Result</title>
                    <p>Xindice queries must always return results. XUpdate queries always
                       return a result with exactly one XML resource that looks like this:</p>
<source><![CDATA[
<?xml version="1.0"?>
<src:modified xmlns:src="http://xml.apache.org/xindice/Query">4</src:modified>
]]></source>
                    <p>It essentially indicates the number of updates that the query performed.
                       To change the format of this XML, you'll have to modify the
                       XUpdate query resolver's source code.</p>
                </section>
            </section>
        </section>
        <section>
            <title>6. Indexes</title>
        </section>
        <section>
            <title>7. The XML:DB drivers</title>
            <section>
                <title>7.1. Embedded driver</title>
            </section>
            <section>
                <title>7.2. XML-RPC driver</title>
            </section>
            <section>
                <title>7.3. Managed driver</title>
                <p>The Managed driver (<code>xindice-managed</code>) is designed for use in environments where the
                life cycle of the xindice database is controlled by an external service. Like the Embeded driver accesses
                a database running in the local vm. Unlike the Embeded driver the Manged driver will <strong>not</strong>
                create the database instance. It will fail to load if the database instance is not available</p>
                <section>
                    <title>7.3.1. Configuraton</title>
                    <p>Configuration of the driver is easy, create an instance of the class. There are two constructors provided,
                    a "no args" default constructure one that takes the name of the database to connect to. The "no args" constructor
                    will attempt to connect a database with the name of "db" or the value of the "xindice.drivers.managed.db" system property.
                    When the second constructor is used the database name is explicitly passed.</p>                        
                </section>
                <section>
                    <title>7.3.2. ManagedServer</title>
                    <p>ManagedServer is a simple class that loads a database for access by the Managed driver. It is by
                    no means the only way to create and register a database instance. Configuration is the same as for
                    the embeded driver. This is suitable for simple tests and standalone applications, but managed environments
                    should provide their own configuration implementations.</p>
                </section>
                <section>
                    <title>7.3.3. Advantages of the managed driver</title>
                    <p>The main advantage is that the database has an explicit lifecycle. With the Emdeded driver database creation
                    is a side effect of access to the client driver. The determination of what lifecycle methods are run when
                    is unclear (for example when is the database closed). By making database instantiation an external task
                    to the driver this problem disappears.</p>
                </section>
            </section>
        </section>
    </body>
</document>
