Imported Upstream version 5.3.21
[platform/upstream/libdb.git] / docs / gsg_txn / JAVA / inmem_txnexample_java.html
1 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
3 <html xmlns="http://www.w3.org/1999/xhtml">
4   <head>
5     <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
6     <title>Base API In-Memory Transaction Example</title>
7     <link rel="stylesheet" href="gettingStarted.css" type="text/css" />
8     <meta name="generator" content="DocBook XSL Stylesheets V1.73.2" />
9     <link rel="start" href="index.html" title="Getting Started with Berkeley DB Transaction Processing" />
10     <link rel="up" href="wrapup.html" title="Chapter 6. Summary and Examples" />
11     <link rel="prev" href="txnexample_dpl.html" title="DPL Transaction Example" />
12   </head>
13   <body>
14     <div xmlns="" class="navheader">
15       <div class="libver">
16         <p>Library Version 11.2.5.3</p>
17       </div>
18       <table width="100%" summary="Navigation header">
19         <tr>
20           <th colspan="3" align="center">Base API In-Memory Transaction Example</th>
21         </tr>
22         <tr>
23           <td width="20%" align="left"><a accesskey="p" href="txnexample_dpl.html">Prev</a> </td>
24           <th width="60%" align="center">Chapter 6. Summary and Examples</th>
25           <td width="20%" align="right"> </td>
26         </tr>
27       </table>
28       <hr />
29     </div>
30     <div class="sect1" lang="en" xml:lang="en">
31       <div class="titlepage">
32         <div>
33           <div>
34             <h2 class="title" style="clear: both"><a id="inmem_txnexample_java"></a>Base API In-Memory Transaction Example</h2>
35           </div>
36         </div>
37       </div>
38       <p>
39         DB is sometimes used for applications that simply need to cache
40         data retrieved from some other location (such as a remote database
41         server). DB is also often used in embedded systems.
42     </p>
43       <p>
44         In both cases, applications may still want to use transactions for
45         atomicity, consistency, and isolation guarantees, but they may want
46         to forgo the durability guarantee entirely. That is, they may want
47         their DB environment and databases kept entirely in-memory so
48         as to avoid the performance impact of unneeded disk I/O.
49     </p>
50       <p>
51         To do this:
52     </p>
53       <div class="itemizedlist">
54         <ul type="disc">
55           <li>
56             <p>
57                 Refrain from specifying a home directory when you open your
58                 environment. The exception to this is if you are using the
59                 <code class="literal">DB_CONFIG</code> configuration file — in
60                 that case you must identify the environment's home
61                 directory so that the configuration file can be found.
62             </p>
63           </li>
64           <li>
65             <p>
66                 Configure your environment to back your regions from
67                 system memory instead of the filesystem.
68             </p>
69           </li>
70           <li>
71             <p>
72                 Configure your logging subsystem such that log files are kept
73                 entirely in-memory.
74             </p>
75           </li>
76           <li>
77             <p>
78                 Increase the size of your in-memory log buffer so that it
79                 is large enough to hold the largest set of concurrent write operations.
80             </p>
81           </li>
82           <li>
83             <p>
84                 Increase the size of your in-memory cache so that it can
85                 hold your entire data set. You do not want your cache to
86                 page to disk.
87             </p>
88           </li>
89           <li>
90             <p>
91                 Do not specify a file name when you open your database(s).
92             </p>
93           </li>
94         </ul>
95       </div>
96       <p>
97         As an example, this section takes the transaction example provided
98         in <a class="xref" href="txnexample_java.html" title="Base API Transaction Example">Base API Transaction Example</a>
99         and it updates that example so that the environment, database, log
100         files, and regions are all kept entirely in-memory. 
101     </p>
102       <p>
103         For illustration purposes, we also modify this example so that 
104         uncommitted reads are no longer used to enable the <code class="methodname">countRecords()</code>
105         method. Instead, we simply provide a transaction handle to
106         <code class="methodname">countRecords()</code> so as to avoid the
107         self-deadlock.
108     </p>
109       <p>
110         The majority of the modifications to the original example are performed in the <code class="classname">TxnGuide</code>
111         example class (see <a class="xref" href="txnexample_java.html#txnguideexample" title="TxnGuide.java">TxnGuide.java</a>). 
112         This is because the majority of the work that we need to do is performed when the environment and
113         databases are opened.
114     </p>
115       <p>
116         To begin, we simplify the beginning of the class a bit. We eliminate some variables that the example no longer
117         needs — specifically variables having to do with the location of the environment and the names of the
118         database files. 
119         We can also remove our <code class="function">usage()</code> method because we no
120         longer require any command line arguments. 
121     </p>
122       <pre class="programlisting">// File TxnGuideInMemory.java
123
124 package db.txn;
125
126 import com.sleepycat.bind.serial.StoredClassCatalog;
127
128 import com.sleepycat.db.Database;
129 import com.sleepycat.db.DatabaseConfig;
130 import com.sleepycat.db.DatabaseException;
131 import com.sleepycat.db.DatabaseType;
132 import com.sleepycat.db.LockDetectMode;
133
134 import com.sleepycat.db.Environment;
135 import com.sleepycat.db.EnvironmentConfig;
136
137 import java.io.File;
138 import java.io.FileNotFoundException;
139
140 <strong class="userinput"><code>public class TxnGuideInMemory {</code></strong>
141
142     // DB handles
143     private static Database myDb = null;
144     private static Database myClassDb = null;
145     private static Environment myEnv = null;
146
147     private static final int NUMTHREADS = 5; </pre>
148       <p>
149     Next, in our <code class="function">main()</code> method, we 
150     remove the call to <code class="methodname">parseArgs()</code> because that only existed in the previous example for
151     collecting the environment home location. Everything else is essentially the same.
152 </p>
153       <pre class="programlisting">    public static void main(String args[]) {
154         try {
155
156             // Open the environment and databases
157             openEnv();
158
159             // Get our class catalog (used to serialize objects)
160             StoredClassCatalog classCatalog =
161                 new StoredClassCatalog(myClassDb);
162
163             // Start the threads
164             DBWriter[] threadArray;
165             threadArray = new DBWriter[NUMTHREADS];
166             for (int i = 0; i &lt; NUMTHREADS; i++) {
167                 threadArray[i] = new DBWriter(myEnv, myDb, classCatalog);
168                 threadArray[i].start();
169             }
170
171             for (int i = 0; i &lt; NUMTHREADS; i++) {
172                 threadArray[i].join();
173             }
174         } catch (Exception e) {
175             System.err.println("<strong class="userinput"><code>TxnGuideInMemory</code></strong>: " + e.toString());
176             e.printStackTrace();
177         } finally {
178             closeEnv();
179         }
180         System.out.println("All done.");
181     } </pre>
182       <p>
183         Next we open our environment as always. However, in doing so we:
184     </p>
185       <div class="itemizedlist">
186         <ul type="disc">
187           <li>
188             <p>
189                 Set <code class="methodname">EnvironmentConfig.setPrivate()</code>
190                 to <code class="literal">true</code>.
191                 This causes our environment to back regions using our
192                 application's heap memory rather than by using the filesystem.
193                 This is the first important step to keeping our DB data
194                 entirely in-memory.
195             </p>
196           </li>
197           <li>
198             <p>
199                 Remove <code class="methodname">runRecovery()</code>
200                 from the environment configuration. Because all our data will be held entirely in memory, recovery is a
201                 non-issue. Note that if we had left the call to <code class="methodname">runRecovery()</code>
202                 in, it would be silently ignored.
203             </p>
204           </li>
205         </ul>
206       </div>
207       <pre class="programlisting">    private static void openEnv() throws DatabaseException {
208         System.out.println("opening env");
209
210         // Set up the environment.
211         EnvironmentConfig myEnvConfig = new EnvironmentConfig();
212
213         <strong class="userinput"><code>// Region files are not backed by the filesystem, they are
214         // backed by heap memory.
215         myEnvConfig.setPrivate(true);</code></strong>
216
217         myEnvConfig.setAllowCreate(true);
218         myEnvConfig.setInitializeCache(true);
219         myEnvConfig.setInitializeLocking(true);
220         myEnvConfig.setInitializeLogging(true);
221         myEnvConfig.setTransactional(true);
222         // EnvironmentConfig.setThreaded(true) is the default behavior 
223         // in Java, so we do not have to do anything to cause the
224         // environment handle to be free-threaded.
225
226         // Indicate that we want db to internally perform deadlock 
227         // detection. Also indicate that the transaction that has
228         // performed the least amount of write activity to
229         // receive the deadlock notification, if any.
230         myEnvConfig.setLockDetectMode(LockDetectMode.MINWRITE); </pre>
231       <p>
232         Now we configure our environment to keep the log files in memory,
233         increase the log buffer size to 10 MB, and increase our in-memory
234         cache to 10 MB. These values should be more than enough for our
235         application's workload.
236       </p>
237       <pre class="programlisting">
238         <strong class="userinput">
239           <code>        // Specify in-memory logging
240         myEnvConfig.setLogInMemory(true);
241         // Specify the size of the in-memory log buffer
242         // Must be large enough to handle the log data created by
243         // the largest transaction.
244         myEnvConfig.setLogBufferSize(10 * 1024 * 1024);
245         // Specify the size of the in-memory cache
246         // Set it large enough so that it won't page.
247         myEnvConfig.setCacheSize(10 * 1024 * 1024); </code>
248         </strong>
249       </pre>
250       <p>
251     Our database configuration is identical to the original example, except that we do not specify
252     <code class="methodname">setReadUncomitted()</code> here. We will be causing our <code class="methodname">countRecords()</code>
253     method to join the transaction rather than perform uncommitted reads, so we do not need our database to support them.
254 </p>
255       <pre class="programlisting">        // Set up the database
256         DatabaseConfig myDbConfig = new DatabaseConfig();
257         myDbConfig.setType(DatabaseType.BTREE);
258         myDbConfig.setAllowCreate(true);
259         myDbConfig.setTransactional(true);
260         myDbConfig.setSortedDuplicates(true);
261         // no DatabaseConfig.setThreaded() method available.
262         // db handles in java are free-threaded so long as the
263         // env is also free-threaded.  </pre>
264       <p>
265     Next, we open the environment. This is
266     identical to how the example previously worked, except that we do not
267     provide a location for the environment's home directory.
268  </p>
269       <pre class="programlisting">        try {
270             // Open the environment
271             myEnv = new Environment(<strong class="userinput"><code>null</code></strong>,    // Env home
272                                     myEnvConfig); </pre>
273       <p>
274         When we open our databases, we also specify <code class="literal">null</code> for the file names. The causes the database
275         to not be backed by the filesystem; that is, the databases are held entirely in memory.
276     </p>
277       <pre class="programlisting">            // Open the database. Do not provide a txn handle. This open
278             // is auto committed because DatabaseConfig.setTransactional()
279             // is true.
280             myDb = myEnv.openDatabase(null,     // txn handle
281                                       <strong class="userinput"><code>null</code></strong>,     // Database file name
282                                       null,     // Database name
283                                       myDbConfig);
284
285             // Used by the bind API for serializing objects 
286             // Class database must not support duplicates
287             myDbConfig.setSortedDuplicates(false);
288             myClassDb = myEnv.openDatabase(null,     // txn handle
289                                            <strong class="userinput"><code>null</code></strong>,     // Database file name
290                                            null,     // Database name,
291                                            myDbConfig);
292         } catch (FileNotFoundException fnfe) {
293             System.err.println("openEnv: " + fnfe.toString());
294             System.exit(-1);
295         }
296     } </pre>
297       <p>
298     After that, our class is unchanged, except for some very minor modifications.
299     Most notably, we remove the <code class="methodname">parseArgs()</code>
300     method from the application, because we no longer need it.
301   </p>
302       <pre class="programlisting">    private static void closeEnv() {
303         System.out.println("Closing env");
304         if (myDb != null ) {
305             try {
306                 myDb.close();
307             } catch (DatabaseException e) {
308                 System.err.println("closeEnv: myDb: " +
309                     e.toString());
310                 e.printStackTrace();
311             }
312         }
313
314         if (myClassDb != null ) {
315             try {
316                 myClassDb.close();
317             } catch (DatabaseException e) {
318                 System.err.println("closeEnv: myClassDb: " +
319                     e.toString());
320                 e.printStackTrace();
321             }
322         }
323
324         if (myEnv != null ) {
325             try {
326                 myEnv.close();
327             } catch (DatabaseException e) {
328                 System.err.println("closeEnv: " + e.toString());
329                 e.printStackTrace();
330             }
331         }
332     }
333
334     <strong class="userinput"><code>private TxnGuideInMemory() {}</code></strong>
335 } </pre>
336       <p>
337         That completes our modifications to this class.
338         We now turn our attention to our <code class="classname">DBWriter</code>
339         class (see <a class="xref" href="txnexample_java.html#dbwriter" title="DBWriter.java">DBWriter.java</a>). 
340         It is unchanged, except for one small modification. In the 
341         <code class="methodname">run()</code> method, we call <code class="methodname">countRecords()</code>
342         with a transaction handle, rather than configuring our entire
343             application for uncommitted reads. Both mechanisms work well-enough
344             for preventing a self-deadlock. However, the individual count
345             in this example will tend to be lower than the counts seen in
346             the previous transaction example, because
347             <code class="function">countRecords()</code> can no longer see records
348             created but not yet committed by other threads. 
349             Additionally, the usage of the transaction handle here will 
350             probably cause more deadlocks than using read-uncommitted does, because more locking is being performed in
351             this case.
352         </p>
353       <pre class="programlisting">package db.txn;
354
355 import com.sleepycat.bind.EntryBinding;
356 import com.sleepycat.bind.serial.StoredClassCatalog;
357 import com.sleepycat.bind.serial.SerialBinding;
358 import com.sleepycat.bind.tuple.StringBinding;
359
360 import com.sleepycat.db.Cursor;
361 import com.sleepycat.db.CursorConfig;
362 import com.sleepycat.db.Database;
363 import com.sleepycat.db.DatabaseEntry;
364 import com.sleepycat.db.DatabaseException;
365 import com.sleepycat.db.DeadlockException;
366 import com.sleepycat.db.Environment;
367 import com.sleepycat.db.LockMode;
368 import com.sleepycat.db.OperationStatus;
369 import com.sleepycat.db.Transaction;
370
371 import java.io.UnsupportedEncodingException;
372 import java.util.Random;
373
374 public class DBWriter extends Thread
375 {
376     private Database myDb = null;
377     private Environment myEnv = null;
378     private EntryBinding dataBinding = null;
379     private Random generator = new Random();
380
381     private static final int MAX_RETRY = 20;
382
383     private static String[] keys = {"key 1", "key 2", "key 3",
384                                     "key 4", "key 5", "key 6",
385                                     "key 7", "key 8", "key 9",
386                                     "key 10"};
387
388
389     // Constructor. Get our DB handles from here
390     DBWriter(Environment env, Database db, StoredClassCatalog scc)
391         throws DatabaseException {
392         myDb = db;
393         myEnv = env;
394         dataBinding = new SerialBinding(scc, PayloadData.class);
395     }
396
397
398     // Thread method that writes a series of records
399     // to the database using transaction protection.
400     // Deadlock handling is demonstrated here.
401     public void run () {
402         Transaction txn = null;
403
404         // Perform 50 transactions
405         for (int i=0; i&lt;50; i++) {
406
407            boolean retry = true;
408            int retry_count = 0;
409            // while loop is used for deadlock retries
410            while (retry) {
411                 // try block used for deadlock detection and
412                 // general db exception handling
413                 try {
414
415                     // Get a transaction
416                     txn = myEnv.beginTransaction(null, null);
417                     // Write 10 records to the db
418                     // for each transaction
419                     for (int j = 0; j &lt; 10; j++) {
420                         // Get the key
421                         DatabaseEntry key = new DatabaseEntry();
422                         StringBinding.stringToEntry(keys[j], key);
423
424                         // Get the data
425                         PayloadData pd = new PayloadData(i+j, getName(),
426                             generator.nextDouble());
427                         DatabaseEntry data = new DatabaseEntry();
428                         dataBinding.objectToEntry(pd, data);
429
430                         // Do the put
431                         myDb.put(txn, key, data);
432                     }
433
434                     // commit
435                     System.out.println(getName() + 
436                         " : committing txn : " + i);
437
438                     System.out.println(getName() + " : Found " +
439                         countRecords(<strong class="userinput"><code>txn</code></strong>) + " records in the database.");
440                     try {
441                         txn.commit();
442                         txn = null;
443                     } catch (DatabaseException e) {
444                         System.err.println("Error on txn commit: " +
445                             e.toString());
446                     }
447                     retry = false;
448
449                 } catch (DeadlockException de) {
450                     System.out.println("################# " + getName() +
451                         " : caught deadlock");
452                     // retry if necessary
453                     if (retry_count &lt; MAX_RETRY) {
454                         System.err.println(getName() +
455                             " : Retrying operation.");
456                         retry = true;
457                         retry_count++;
458                     } else {
459                         System.err.println(getName() +
460                             " : out of retries. Giving up.");
461                         retry = false;
462                     }
463                 } catch (DatabaseException e) {
464                     // abort and don't retry
465                     retry = false;
466                     System.err.println(getName() +
467                         " : caught exception: " + e.toString());
468                     System.err.println(getName() +
469                         " : errno: " + e.getErrno());
470                     e.printStackTrace();
471                 } finally {
472                     if (txn != null) {
473                         try {
474                             txn.abort();
475                         } catch (Exception e) {
476                             System.err.println(
477                                 "Error aborting transaction: " + 
478                                 e.toString());
479                             e.printStackTrace();
480                         }
481                     }
482                 }
483             }
484         }
485     } </pre>
486       <p>
487     Next we update <code class="methodname">countRecords()</code>. The only difference
488     here is that we no longer specify <code class="methodname">CursorConfig.setReadUncomitted()</code> when
489     we open our cursor. Note that even this minor change is not required.
490     If we do not configure our database to support uncommitted reads,
491     <code class="methodname">CursorConfig.setReadUncomitted()</code> is silently
492     ignored. However, we remove the property anyway from the cursor open so as to
493     avoid confusion.
494 </p>
495       <pre class="programlisting">    // This simply counts the number of records contained in the
496     // database and returns the result. You can use this method
497     // in three ways:
498     //
499     // First call it with an active txn handle.
500     // Secondly, configure the cursor for uncommitted reads
501     // Third, call count_records AFTER the writer has committed
502     //    its transaction.
503     //
504     // If you do none of these things, the writer thread will 
505     // self-deadlock.
506     //
507     // Note that this method exists only for illustrative purposes.
508     // A more straight-forward way to count the number of records in
509     // a database is to use the Database.getStats() method.
510     private int countRecords(Transaction txn)  throws DatabaseException {
511         DatabaseEntry key = new DatabaseEntry();
512         DatabaseEntry data = new DatabaseEntry();
513         int count = 0;
514         Cursor cursor = null;
515
516         try {
517             // Get the cursor
518             CursorConfig cc = new CursorConfig();
519             cc.setReadUncomitted(true);
520             cursor = myDb.openCursor(txn, cc);
521             while (cursor.getNext(key, data, LockMode.DEFAULT) ==
522                     OperationStatus.SUCCESS) {
523
524                     count++;
525             }
526         } finally {
527             if (cursor != null) {
528                 cursor.close();
529             }
530         }
531
532         return count;
533
534     }
535 } </pre>
536       <p>
537     This completes our in-memory transactional example. If you would like to
538     experiment with this code, you can find the example in the following
539     location in your DB distribution:
540 </p>
541       <pre class="programlisting"><span class="emphasis"><em>DB_INSTALL</em></span>/examples_java/src/db/txn</pre>
542     </div>
543     <div class="navfooter">
544       <hr />
545       <table width="100%" summary="Navigation footer">
546         <tr>
547           <td width="40%" align="left"><a accesskey="p" href="txnexample_dpl.html">Prev</a> </td>
548           <td width="20%" align="center">
549             <a accesskey="u" href="wrapup.html">Up</a>
550           </td>
551           <td width="40%" align="right"> </td>
552         </tr>
553         <tr>
554           <td width="40%" align="left" valign="top">DPL Transaction Example </td>
555           <td width="20%" align="center">
556             <a accesskey="h" href="index.html">Home</a>
557           </td>
558           <td width="40%" align="right" valign="top"> </td>
559         </tr>
560       </table>
561     </div>
562   </body>
563 </html>