mirror of
https://github.com/berkeleydb/libdb.git
synced 2024-11-16 17:16:25 +00:00
348 lines
15 KiB
HTML
348 lines
15 KiB
HTML
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||
<head>
|
||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||
<title>Dbstl persistence</title>
|
||
<link rel="stylesheet" href="gettingStarted.css" type="text/css" />
|
||
<meta name="generator" content="DocBook XSL Stylesheets V1.73.2" />
|
||
<link rel="start" href="index.html" title="Berkeley DB Programmer's Reference Guide" />
|
||
<link rel="up" href="stl.html" title="Chapter 7. Standard Template Library API" />
|
||
<link rel="prev" href="stl_complex_rw.html" title="Store and Retrieve data or objects of complex types" />
|
||
<link rel="next" href="stl_container_specific.html" title="Dbstl container specific notes" />
|
||
</head>
|
||
<body>
|
||
<div xmlns="" class="navheader">
|
||
<div class="libver">
|
||
<p>Library Version 11.2.5.2</p>
|
||
</div>
|
||
<table width="100%" summary="Navigation header">
|
||
<tr>
|
||
<th colspan="3" align="center">Dbstl persistence</th>
|
||
</tr>
|
||
<tr>
|
||
<td width="20%" align="left"><a accesskey="p" href="stl_complex_rw.html">Prev</a> </td>
|
||
<th width="60%" align="center">Chapter 7. Standard Template Library API</th>
|
||
<td width="20%" align="right"> <a accesskey="n" href="stl_container_specific.html">Next</a></td>
|
||
</tr>
|
||
</table>
|
||
<hr />
|
||
</div>
|
||
<div class="sect1" lang="en" xml:lang="en">
|
||
<div class="titlepage">
|
||
<div>
|
||
<div>
|
||
<h2 class="title" style="clear: both"><a id="stl_persistence"></a>Dbstl persistence</h2>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="toc">
|
||
<dl>
|
||
<dt>
|
||
<span class="sect2">
|
||
<a href="stl_persistence.html#directdbget">Direct database get</a>
|
||
</span>
|
||
</dt>
|
||
<dt>
|
||
<span class="sect2">
|
||
<a href="stl_persistence.html#chg_persistence">Change persistence</a>
|
||
</span>
|
||
</dt>
|
||
<dt>
|
||
<span class="sect2">
|
||
<a href="stl_persistence.html#obj_life_persistence">Object life time and persistence </a>
|
||
</span>
|
||
</dt>
|
||
</dl>
|
||
</div>
|
||
<p>
|
||
The following sections provide information on how to achieve
|
||
persistence using dbstl.
|
||
</p>
|
||
<div class="sect2" lang="en" xml:lang="en">
|
||
<div class="titlepage">
|
||
<div>
|
||
<div>
|
||
<h3 class="title"><a id="directdbget"></a>Direct database get</h3>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p>
|
||
Each container has a <span class="bold"><strong>begin()</strong></span> method
|
||
which produces an iterator. These
|
||
<span class="bold"><strong>begin</strong></span> methods take a boolean parameter,
|
||
<span class="bold"><strong>directdb_get</strong></span>, which controls the
|
||
caching behavior of the iterator. The default value of this parameter
|
||
is <code class="literal">true</code>.
|
||
</p>
|
||
<p>
|
||
If <span class="bold"><strong>directdb_get</strong></span> is
|
||
<code class="literal">true</code>, then the persistent object is fetched anew
|
||
from the database each time the iterator is dereferenced as a pointer
|
||
by use of the star-operator
|
||
(<span class="bold"><strong>*iterator</strong></span>) or by use of the arrow-operator
|
||
(<span class="bold"><strong>iterator->member</strong></span>). If
|
||
<span class="bold"><strong>directdb_get</strong></span> is <code class="literal">false</code>, then
|
||
the first dereferencing of the iterator fetches the object from the
|
||
database, but later dereferences can return cached data.
|
||
</p>
|
||
<p>
|
||
With <span class="bold"><strong>directdb_get</strong></span> set to <code class="literal">true</code>, if you call:
|
||
</p>
|
||
<pre class="programlisting">(*iterator).datamember1=new-value1;
|
||
(*iterator).datamember2=new-value2; </pre>
|
||
<p>
|
||
then the assignment to <code class="literal">datamember1</code> will be lost,
|
||
because the second dereferencing of the iterator would cause the cached
|
||
copy of the object to be overwritten by the object's persistent data
|
||
from the database.
|
||
</p>
|
||
<p>
|
||
You also can use the arrow operator like this:
|
||
</p>
|
||
<pre class="programlisting">iterator->datamember1=new-value1;
|
||
iterator->datamember2=new-value2; </pre>
|
||
<p>
|
||
This works exactly the same way as <span class="bold"><strong>iterator::operator*</strong></span>.
|
||
For this reason, the same caching rules apply to arrow operators as they do
|
||
for star operators.
|
||
</p>
|
||
<p>
|
||
One way to avoid this problem is to create a reference to the object,
|
||
and use it to access the object:
|
||
</p>
|
||
<pre class="programlisting">container::value_type &ref = *iterator;
|
||
ref.datamember1=new-value1;
|
||
ref.datamember2=new-value2;
|
||
...// more member function calls and datamember assignments
|
||
ref._DB_STL_StoreElement(); </pre>
|
||
<p>
|
||
The above code will not lose the newly assigned value of <code class="literal">ref.datamember1</code>
|
||
in the way that the previous example did.
|
||
</p>
|
||
<p>
|
||
In order to avoid these complications, you can assign to the object
|
||
referenced by an iterator with another object of the same type like this:
|
||
</p>
|
||
<pre class="programlisting">container::value_type obj2;
|
||
obj2.datamember1 = new-value1;
|
||
obj2.datamember2 = new-value2;
|
||
*itr = obj2; </pre>
|
||
<p>
|
||
This code snippet causes the new values in <code class="literal">obj2</code> to
|
||
be stored into the underlying database.
|
||
</p>
|
||
<p>
|
||
If you have two iterators going through the same container like this:
|
||
</p>
|
||
<pre class="programlisting">
|
||
for (iterator1 = v.begin(), iterator2 = v.begin();
|
||
iterator1 != v.end();
|
||
++iterator1, ++iterator2) {
|
||
*iterator1 = new_value;
|
||
print(*iterator2);
|
||
} </pre>
|
||
<p>
|
||
then the printed value will depend on the value of
|
||
<span class="bold"><strong>directdb_get</strong></span> with which the
|
||
iterator had been created. If <span class="bold"><strong>directdb_get</strong></span>
|
||
is <code class="literal">false</code>, then the original, persistent value is
|
||
printed; otherwise the newly assigned value is returned from the
|
||
cache when <code class="literal">iterator2</code> is dereferenced. This
|
||
happens because each iterator has its own cached copy of the
|
||
persistent object, and the dereferencing of
|
||
<code class="literal">iterator2</code> refreshes
|
||
<code class="literal">iterator2</code>'s copy from the database, retrieving
|
||
the value stored by the assignment to
|
||
<code class="literal">*iterator1</code>.
|
||
</p>
|
||
<p>
|
||
Alternatively, you can set <span class="bold"><strong>directdb_get
|
||
</strong></span> to <code class="literal">false</code> and call
|
||
<code class="methodname">iterator2->refresh()</code> immediately before
|
||
the dereferencing of <code class="literal">iterator2</code>, so that
|
||
<code class="literal">iterator2</code>'s cached value is refreshed.
|
||
</p>
|
||
<p>
|
||
If <span class="bold"><strong>directdb_get</strong></span> is
|
||
<code class="literal">false</code>, a few of the tests in dbstl's test kit
|
||
will fail. This is because the above contrived case appears in
|
||
several of C++ STL tests. Consequently, the default value of the
|
||
<span class="bold"><strong>directdb_get</strong></span> parameter in the
|
||
<code class="methodname">container::begin()</code> methods is
|
||
<code class="literal">true</code>. If your use cases avoid such bizarre usage
|
||
of iterators, you can set it to <code class="literal">false</code>, which
|
||
makes the iterator read operation faster.
|
||
</p>
|
||
</div>
|
||
<div class="sect2" lang="en" xml:lang="en">
|
||
<div class="titlepage">
|
||
<div>
|
||
<div>
|
||
<h3 class="title"><a id="chg_persistence"></a>Change persistence</h3>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p>
|
||
If you modify the object to which an iterator refers by using one
|
||
of the following:
|
||
</p>
|
||
<pre class="programlisting">(*iterator).member_function_call()</pre>
|
||
<p>
|
||
or
|
||
</p>
|
||
<pre class="programlisting">(*iterator).data_member = new_value</pre>
|
||
<p>
|
||
then you should call
|
||
<code class="methodname">iterator->_DB_STL_StoreElement()</code> to
|
||
store the change. Otherwise the change is lost after the
|
||
iterator moves on to other elements.
|
||
</p>
|
||
<p>
|
||
If you are storing a sequence, and you modified some part of it, you
|
||
should also call
|
||
<code class="methodname">iterator->_DB_STL_StoreElement()</code>
|
||
before moving the iterator.
|
||
</p>
|
||
<p>
|
||
And in both cases, if <span class="bold"><strong>directdb_get</strong></span>
|
||
is <code class="literal">true</code> (this is the default value), you should
|
||
call <code class="methodname">_DB_STL_StoreElement()</code> after the
|
||
change and before the next iterator movement OR the next
|
||
dereferencing of the iterator by the star or arrow operators
|
||
(<code class="literal">iterator::operator*</code> or
|
||
<code class="literal">iterator::operator-></code>). Otherwise, you will
|
||
lose the change.
|
||
</p>
|
||
<p>
|
||
If you update the element by assigning to a dereferenced iterator like
|
||
this:
|
||
</p>
|
||
<pre class="programlisting">*iterator = new_element;</pre>
|
||
<p>
|
||
then you never have to call
|
||
<code class="methodname">_DB_STL_StoreElement()</code> because the change
|
||
is stored in the database automatically.
|
||
</p>
|
||
</div>
|
||
<div class="sect2" lang="en" xml:lang="en">
|
||
<div class="titlepage">
|
||
<div>
|
||
<div>
|
||
<h3 class="title"><a id="obj_life_persistence"></a>Object life time and persistence </h3>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p>
|
||
Dbstl is an interface to Berkeley DB, so it is used to store data
|
||
persistently. This is really a different purpose from that of
|
||
regular C++ STL. This difference in their goals has implications on
|
||
expected object lifetime: In standard STL, when you store an object
|
||
A of type ID into C++ stl vector V using V.push_back(A), if a
|
||
proper copy constructor is provided in A's class type, then the
|
||
copy of A (call it B) and everything in B, such as another object C
|
||
pointed to by B's data member B.c_ptr, will be stored in V and will
|
||
live as long as B is still in V and V is alive. B will be destroyed
|
||
when V is destroyed or B is erased from V.
|
||
</p>
|
||
<p>
|
||
This is not true for dbstl, which will copy A's data and store it
|
||
in the underlying database. The copy is by default a shallow copy,
|
||
but users can register their object marshalling and unmarshalling
|
||
functions using the <code class="classname">DbstlElemTraits</code> class
|
||
template. So if A is passed to a <code class="classname">db_vector</code>
|
||
container, <code class="literal">dv</code>, by using
|
||
<code class="literal">dv.push_back(A)</code>, then dbstl copies A's data
|
||
using the registered functions, and stores data into the underlying
|
||
database. Consequently, A will be valid, even if the container is
|
||
destroyed, because it is stored into the database.
|
||
</p>
|
||
<p>
|
||
If the copy is simply a shallow copy, and A is later destroyed, then
|
||
the pointer stored in the database will become invalid. The next time
|
||
we use the retrieved object, we will be using an invalid pointer, which
|
||
probably will result in errors. To avoid this, store the referred
|
||
object C rather than the pointer member A.c_ptr itself, by registering
|
||
the right marshalling/unmarshalling function with
|
||
<code class="classname">DbstlElemTraits</code>.
|
||
</p>
|
||
<p>
|
||
For example, consider the following example class declaration:
|
||
</p>
|
||
<pre class="programlisting">class ID
|
||
{
|
||
public:
|
||
string Name;
|
||
int Score;
|
||
}; </pre>
|
||
<p>
|
||
Here, the class ID has a data member <span class="bold"><strong>Name</strong></span>, which refers to a memory address of
|
||
the actual characters in the string. If we simply shallow copy an
|
||
object, <code class="literal">id</code>, of class ID to store it, then the
|
||
stored data, <code class="literal">idd</code>, is invalid when
|
||
<code class="literal">id</code> is destroyed. This is because
|
||
<code class="literal">idd</code> and <code class="literal">id</code> refer to a common
|
||
memory address which is the base address of the memory space storing
|
||
all characters in the string, and this memory space is released when
|
||
<code class="literal">id</code> is destroyed. So <code class="literal">idd</code> will be
|
||
referring to an invalid address. The next time we retrieve
|
||
<code class="literal">idd</code> and use it, there will probably be memory
|
||
corruption.
|
||
</p>
|
||
<p>
|
||
The way to store <code class="literal">id</code> is to write a marshal/unmarshal
|
||
function pair like this:
|
||
</p>
|
||
<pre class="programlisting">void copy_id(void *dest, const ID&elem)
|
||
{
|
||
memcpy(dest, &elem.Score, sizeof(elem.Score));
|
||
char *p = ((char *)dest) + sizeof(elem.Score);
|
||
strcpy(p, elem.Name.c_str());
|
||
}
|
||
|
||
void restore_id(ID& dest, const void *srcdata)
|
||
{
|
||
memcpy(&dest.Score, srcdata, sizeof(dest.Score));
|
||
const char *p = ((char *)srcdata) + sizeof(dest.Score);
|
||
dest.Name = p;
|
||
}
|
||
|
||
size_t size_id(const ID& elem)
|
||
{
|
||
return sizeof(elem.Score) + elem.Name.size() +
|
||
1;// store the '\0' char.
|
||
} </pre>
|
||
<p>
|
||
Then register the above functions before storing any instance of
|
||
<code class="classname">ID</code>:
|
||
</p>
|
||
<pre class="programlisting">DbstlElemTraits<ID>::instance()->set_copy_function(copy_id);
|
||
DbstlElemTraits<ID>::instance()->set_size_function(size_id);
|
||
DbstlElemTraits<ID>::instance()->set_restore_function(restore_id); </pre>
|
||
<p>
|
||
This way, the actual data of instances of ID are stored, and so the
|
||
data will persist even if the container itself is destroyed.
|
||
</p>
|
||
</div>
|
||
</div>
|
||
<div class="navfooter">
|
||
<hr />
|
||
<table width="100%" summary="Navigation footer">
|
||
<tr>
|
||
<td width="40%" align="left"><a accesskey="p" href="stl_complex_rw.html">Prev</a> </td>
|
||
<td width="20%" align="center">
|
||
<a accesskey="u" href="stl.html">Up</a>
|
||
</td>
|
||
<td width="40%" align="right"> <a accesskey="n" href="stl_container_specific.html">Next</a></td>
|
||
</tr>
|
||
<tr>
|
||
<td width="40%" align="left" valign="top">Store and Retrieve data or objects of complex types </td>
|
||
<td width="20%" align="center">
|
||
<a accesskey="h" href="index.html">Home</a>
|
||
</td>
|
||
<td width="40%" align="right" valign="top"> Dbstl container specific notes</td>
|
||
</tr>
|
||
</table>
|
||
</div>
|
||
</body>
|
||
</html>
|