summaryrefslogtreecommitdiff
path: root/examples_java/src/db
diff options
context:
space:
mode:
Diffstat (limited to 'examples_java/src/db')
-rw-r--r--examples_java/src/db/AccessExample.java182
-rw-r--r--examples_java/src/db/BtRecExample.java287
-rw-r--r--examples_java/src/db/BulkAccessExample.java161
-rw-r--r--examples_java/src/db/BulkAccessNIOExample.java180
-rw-r--r--examples_java/src/db/EnvExample.java144
-rw-r--r--examples_java/src/db/GettingStarted/ExampleDatabaseLoad.java231
-rw-r--r--examples_java/src/db/GettingStarted/ExampleDatabaseRead.java205
-rw-r--r--examples_java/src/db/GettingStarted/Inventory.java70
-rw-r--r--examples_java/src/db/GettingStarted/InventoryBinding.java54
-rw-r--r--examples_java/src/db/GettingStarted/ItemNameKeyCreator.java45
-rw-r--r--examples_java/src/db/GettingStarted/MyDbs.java165
-rw-r--r--examples_java/src/db/GettingStarted/Vendor.java90
-rw-r--r--examples_java/src/db/GettingStarted/inventory.txt800
-rw-r--r--examples_java/src/db/GettingStarted/vendors.txt6
-rw-r--r--examples_java/src/db/LockExample.java226
-rw-r--r--examples_java/src/db/SequenceExample.java92
-rw-r--r--examples_java/src/db/TpcbExample.java789
-rw-r--r--examples_java/src/db/repquote/RepConfig.java111
-rw-r--r--examples_java/src/db/repquote/RepQuoteEnvironment.java59
-rw-r--r--examples_java/src/db/repquote/RepQuoteExample.java669
-rw-r--r--examples_java/src/db/repquote/RepRemoteHost.java29
-rw-r--r--examples_java/src/db/repquote_gsg/RepConfig.java105
-rw-r--r--examples_java/src/db/repquote_gsg/RepQuoteEnvironment.java40
-rw-r--r--examples_java/src/db/repquote_gsg/RepQuoteExampleGSG.java383
-rw-r--r--examples_java/src/db/repquote_gsg/SimpleConfig.java32
-rw-r--r--examples_java/src/db/repquote_gsg/SimpleTxn.java229
-rw-r--r--examples_java/src/db/txn/DBWriter.java213
-rw-r--r--examples_java/src/db/txn/PayloadData.java27
-rw-r--r--examples_java/src/db/txn/TxnGuide.java181
-rw-r--r--examples_java/src/db/txn/TxnGuideInMemory.java172
30 files changed, 5977 insertions, 0 deletions
diff --git a/examples_java/src/db/AccessExample.java b/examples_java/src/db/AccessExample.java
new file mode 100644
index 0000000..841dae5
--- /dev/null
+++ b/examples_java/src/db/AccessExample.java
@@ -0,0 +1,182 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 1997-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+
+package db;
+
+import com.sleepycat.db.*;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.InputStreamReader;
+import java.io.IOException;
+import java.io.PrintStream;
+
+class AccessExample {
+ private static final int EXIT_SUCCESS = 0;
+ private static final int EXIT_FAILURE = 1;
+
+ public AccessExample() {
+ }
+
+ public static void usage() {
+ System.out.println("usage: java " +
+ "db.AccessExample [-r] [database]\n");
+ System.exit(EXIT_FAILURE);
+ }
+
+ public static void main(String[] argv) {
+ boolean removeExistingDatabase = false;
+ String databaseName = "access.db";
+
+ for (int i = 0; i < argv.length; i++) {
+ if (argv[i].equals("-r"))
+ removeExistingDatabase = true;
+ else if (argv[i].equals("-?"))
+ usage();
+ else if (argv[i].startsWith("-"))
+ usage();
+ else {
+ if ((argv.length - i) != 1)
+ usage();
+ databaseName = argv[i];
+ break;
+ }
+ }
+
+ try {
+ AccessExample app = new AccessExample();
+ app.run(removeExistingDatabase, databaseName);
+ } catch (DatabaseException dbe) {
+ System.err.println("AccessExample: " + dbe.toString());
+ System.exit(EXIT_FAILURE);
+ } catch (FileNotFoundException fnfe) {
+ System.err.println("AccessExample: " + fnfe.toString());
+ System.exit(EXIT_FAILURE);
+ }
+ System.exit(EXIT_SUCCESS);
+ }
+
+ // Prompts for a line, and keeps prompting until a non blank
+ // line is returned. Returns null on error.
+ //
+ public static String askForLine(InputStreamReader reader,
+ PrintStream out, String prompt) {
+ String result = "";
+ while (result != null && result.length() == 0) {
+ out.print(prompt);
+ out.flush();
+ result = getLine(reader);
+ }
+ return result;
+ }
+
+ // Not terribly efficient, but does the job.
+ // Works for reading a line from stdin or a file.
+ // Returns null on EOF. If EOF appears in the middle
+ // of a line, returns that line, then null on next call.
+ //
+ public static String getLine(InputStreamReader reader) {
+ StringBuffer b = new StringBuffer();
+ int c;
+ try {
+ while ((c = reader.read()) != -1 && c != '\n') {
+ if (c != '\r')
+ b.append((char)c);
+ }
+ } catch (IOException ioe) {
+ c = -1;
+ }
+
+ if (c == -1 && b.length() == 0)
+ return null;
+ else
+ return b.toString();
+ }
+
+ public void run(boolean removeExistingDatabase, String databaseName)
+ throws DatabaseException, FileNotFoundException {
+
+ // Remove the previous database.
+ if (removeExistingDatabase)
+ new File(databaseName).delete();
+
+ // Create the database object.
+ // There is no environment for this simple example.
+ DatabaseConfig dbConfig = new DatabaseConfig();
+ dbConfig.setErrorStream(System.err);
+ dbConfig.setErrorPrefix("AccessExample");
+ dbConfig.setType(DatabaseType.BTREE);
+ dbConfig.setAllowCreate(true);
+ Database table = new Database(databaseName, null, dbConfig);
+
+ //
+ // Insert records into the database, where the key is the user
+ // input and the data is the user input in reverse order.
+ //
+ InputStreamReader reader = new InputStreamReader(System.in);
+
+ for (;;) {
+ String line = askForLine(reader, System.out, "input> ");
+ if (line == null)
+ break;
+
+ String reversed = (new StringBuffer(line)).reverse().toString();
+
+ // See definition of StringDbt below
+ //
+ StringEntry key = new StringEntry(line);
+ StringEntry data = new StringEntry(reversed);
+
+ try {
+ if (table.putNoOverwrite(null, key, data) == OperationStatus.KEYEXIST)
+ System.out.println("Key " + line + " already exists.");
+ } catch (DatabaseException dbe) {
+ System.out.println(dbe.toString());
+ }
+ }
+
+ // Acquire an iterator for the table.
+ Cursor cursor;
+ cursor = table.openCursor(null, null);
+
+ // Walk through the table, printing the key/data pairs.
+ // See class StringDbt defined below.
+ //
+ StringEntry key = new StringEntry();
+ StringEntry data = new StringEntry();
+ while (cursor.getNext(key, data, null) == OperationStatus.SUCCESS)
+ System.out.println(key.getString() + " : " + data.getString());
+ cursor.close();
+ table.close();
+ }
+
+ // Here's an example of how you can extend DatabaseEntry in a
+ // straightforward way to allow easy storage/retrieval of strings,
+ // or whatever kind of data you wish. We've declared it as a static
+ // inner class, but it need not be.
+ //
+ static /*inner*/
+ class StringEntry extends DatabaseEntry {
+ StringEntry() {
+ }
+
+ StringEntry(String value) {
+ setString(value);
+ }
+
+ void setString(String value) {
+ byte[] data = value.getBytes();
+ setData(data);
+ setSize(data.length);
+ }
+
+ String getString() {
+ return new String(getData(), getOffset(), getSize());
+ }
+ }
+}
diff --git a/examples_java/src/db/BtRecExample.java b/examples_java/src/db/BtRecExample.java
new file mode 100644
index 0000000..71beda0
--- /dev/null
+++ b/examples_java/src/db/BtRecExample.java
@@ -0,0 +1,287 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 1997-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+
+package db;
+
+import com.sleepycat.db.*;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.InputStreamReader;
+import java.io.IOException;
+import java.io.PrintStream;
+
+public class BtRecExample {
+ static final String progname = "BtRecExample"; // Program name.
+ static final String database = "access.db";
+ static final String wordlist = "../test/wordlist";
+
+ BtRecExample(BufferedReader reader)
+ throws DatabaseException, IOException, FileNotFoundException {
+
+ OperationStatus status;
+
+ // Remove the previous database.
+ File f = new File(database);
+ f.delete();
+
+ DatabaseConfig config = new DatabaseConfig();
+
+ config.setErrorStream(System.err);
+ config.setErrorPrefix(progname);
+ config.setPageSize(1024); // 1K page sizes.
+
+ config.setBtreeRecordNumbers(true);
+ config.setType(DatabaseType.BTREE);
+ config.setAllowCreate(true);
+ db = new Database(database, null, config);
+
+ //
+ // Insert records into the database, where the key is the word
+ // preceded by its record number, and the data is the same, but
+ // in reverse order.
+ //
+
+ for (int cnt = 1; cnt <= 1000; ++cnt) {
+ String numstr = String.valueOf(cnt);
+ while (numstr.length() < 4)
+ numstr = "0" + numstr;
+ String buf = numstr + '_' + reader.readLine();
+ StringBuffer rbuf = new StringBuffer(buf).reverse();
+
+ StringEntry key = new StringEntry(buf);
+ StringEntry data = new StringEntry(rbuf.toString());
+
+ status = db.putNoOverwrite(null, key, data);
+ if (status != OperationStatus.SUCCESS &&
+ status!= OperationStatus.KEYEXIST)
+ throw new DatabaseException("Database.put failed " + status);
+ }
+ }
+
+ void run() throws DatabaseException {
+ int recno;
+ OperationStatus status;
+
+ // Acquire a cursor for the database.
+ cursor = db.openCursor(null, null);
+
+ //
+ // Prompt the user for a record number, then retrieve and display
+ // that record.
+ //
+ InputStreamReader reader = new InputStreamReader(System.in);
+
+ for (;;) {
+ // Get a record number.
+ String line = askForLine(reader, System.out, "recno #> ");
+ if (line == null)
+ break;
+
+ try {
+ recno = Integer.parseInt(line);
+ } catch (NumberFormatException nfe) {
+ System.err.println("Bad record number: " + nfe);
+ continue;
+ }
+
+ //
+ // Start with a fresh key each time, the db.get() routine returns
+ // the key and data pair, not just the key!
+ //
+ RecnoStringEntry key = new RecnoStringEntry(recno, 4);
+ RecnoStringEntry data = new RecnoStringEntry(4);
+
+ status = cursor.getSearchRecordNumber(key, data, null);
+ if (status != OperationStatus.SUCCESS)
+ throw new DatabaseException("Cursor.setRecno failed: " + status);
+
+ // Display the key and data.
+ show("k/d\t", key, data);
+
+ // Move the cursor a record forward.
+ status = cursor.getNext(key, data, null);
+ if (status != OperationStatus.SUCCESS)
+ throw new DatabaseException("Cursor.getNext failed: " + status);
+
+ // Display the key and data.
+ show("next\t", key, data);
+
+ RecnoStringEntry datano = new RecnoStringEntry(4);
+
+ //
+ // Retrieve the record number for the following record into
+ // local memory.
+ //
+ status = cursor.getRecordNumber(datano, null);
+ if (status != OperationStatus.SUCCESS &&
+ status != OperationStatus.NOTFOUND &&
+ status != OperationStatus.KEYEMPTY)
+ throw new DatabaseException("Cursor.get failed: " + status);
+ else {
+ recno = datano.getRecordNumber();
+ System.out.println("retrieved recno: " + recno);
+ }
+ }
+
+ cursor.close();
+ cursor = null;
+ }
+
+ //
+ // Print out the number of records in the database.
+ //
+ void stats() throws DatabaseException {
+ BtreeStats stats;
+
+ stats = (BtreeStats)db.getStats(null, null);
+ System.out.println(progname + ": database contains " +
+ stats.getNumData() + " records");
+ }
+
+ void show(String msg, RecnoStringEntry key, RecnoStringEntry data)
+ throws DatabaseException {
+
+ System.out.println(msg + key.getString() + ": " + data.getString());
+ }
+
+ public void shutdown() throws DatabaseException {
+ if (cursor != null) {
+ cursor.close();
+ cursor = null;
+ }
+ if (db != null) {
+ db.close();
+ db = null;
+ }
+ }
+
+ public static void main(String[] argv) {
+ try {
+ // Open the word database.
+ FileReader freader = new FileReader(wordlist);
+
+ BtRecExample app = new BtRecExample(new BufferedReader(freader));
+
+ // Close the word database.
+ freader.close();
+ freader = null;
+
+ app.stats();
+ app.run();
+ } catch (FileNotFoundException fnfe) {
+ System.err.println(progname + ": unexpected open error " + fnfe);
+ System.exit (1);
+ } catch (IOException ioe) {
+ System.err.println(progname + ": open " + wordlist + ": " + ioe);
+ System.exit (1);
+ } catch (DatabaseException dbe) {
+ System.err.println("Exception: " + dbe);
+ System.exit(dbe.getErrno());
+ }
+
+ System.exit(0);
+ }
+
+ // Prompts for a line, and keeps prompting until a non blank
+ // line is returned. Returns null on error.
+ //
+ public static String askForLine(InputStreamReader reader,
+ PrintStream out, String prompt) {
+ String result = "";
+ while (result != null && result.length() == 0) {
+ out.print(prompt);
+ out.flush();
+ result = getLine(reader);
+ }
+ return result;
+ }
+
+ // Not terribly efficient, but does the job.
+ // Works for reading a line from stdin or a file.
+ // Returns null on EOF. If EOF appears in the middle
+ // of a line, returns that line, then null on next call.
+ //
+ public static String getLine(InputStreamReader reader) {
+ StringBuffer b = new StringBuffer();
+ int c;
+ try {
+ while ((c = reader.read()) != -1 && c != '\n') {
+ if (c != '\r')
+ b.append((char)c);
+ }
+ } catch (IOException ioe) {
+ c = -1;
+ }
+
+ if (c == -1 && b.length() == 0)
+ return null;
+ else
+ return b.toString();
+ }
+
+ private Cursor cursor;
+ private Database db;
+
+ // Here's an example of how you can extend DatabaseEntry in a
+ // straightforward way to allow easy storage/retrieval of strings.
+ // We've declared it as a static inner class, but it need not be.
+ //
+ static class StringEntry extends DatabaseEntry {
+ StringEntry() {}
+
+ StringEntry(String value) {
+ setString(value);
+ }
+
+ void setString(String value) {
+ byte[] data = value.getBytes();
+ setData(data);
+ setSize(data.length);
+ }
+
+ String getString() {
+ return new String(getData(), 0, getSize());
+ }
+ }
+
+ // Here's an example of how you can extend DatabaseEntry to store
+ // (potentially) both recno's and strings in the same structure.
+ //
+ static class RecnoStringEntry extends DatabaseEntry {
+ RecnoStringEntry(int maxsize) {
+ this(0, maxsize); // let other constructor do most of the work
+ }
+
+ RecnoStringEntry(int value, int maxsize) {
+ arr = new byte[maxsize];
+ setRecordNumber(value);
+ setSize(arr.length);
+ }
+
+ RecnoStringEntry(String value) {
+ byte[] data = value.getBytes();
+ setData(data); // use our local array for data
+ setUserBuffer(data.length, true);
+ }
+
+ void setString(String value) {
+ byte[] data = value.getBytes();
+ setData(data);
+ setSize(data.length);
+ }
+
+ String getString() {
+ return new String(getData(), getOffset(), getSize());
+ }
+
+ byte[] arr;
+ }
+}
diff --git a/examples_java/src/db/BulkAccessExample.java b/examples_java/src/db/BulkAccessExample.java
new file mode 100644
index 0000000..6d0be08
--- /dev/null
+++ b/examples_java/src/db/BulkAccessExample.java
@@ -0,0 +1,161 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 1997-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package db;
+
+import com.sleepycat.db.*;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.InputStreamReader;
+import java.io.IOException;
+import java.io.PrintStream;
+
+class BulkAccessExample {
+ private static final String FileName = "access.db";
+
+ public BulkAccessExample() {
+ }
+
+ public static void main(String[] argv) {
+ try {
+ BulkAccessExample app = new BulkAccessExample();
+ app.run();
+ } catch (DatabaseException dbe) {
+ System.err.println("BulkAccessExample: " + dbe.toString());
+ System.exit(1);
+ } catch (FileNotFoundException fnfe) {
+ System.err.println("BulkAccessExample: " + fnfe.toString());
+ System.exit(1);
+ }
+ System.exit(0);
+ }
+
+ // Prompts for a line, and keeps prompting until a non blank
+ // line is returned. Returns null on error.
+ //
+ public static String askForLine(InputStreamReader reader,
+ PrintStream out, String prompt) {
+ String result = "";
+ while (result != null && result.length() == 0) {
+ out.print(prompt);
+ out.flush();
+ result = getLine(reader);
+ }
+ return result;
+ }
+
+ // Not terribly efficient, but does the job.
+ // Works for reading a line from stdin or a file.
+ // Returns null on EOF. If EOF appears in the middle
+ // of a line, returns that line, then null on next call.
+ //
+ public static String getLine(InputStreamReader reader) {
+ StringBuffer b = new StringBuffer();
+ int c;
+ try {
+ while ((c = reader.read()) != -1 && c != '\n') {
+ if (c != '\r')
+ b.append((char)c);
+ }
+ } catch (IOException ioe) {
+ c = -1;
+ }
+
+ if (c == -1 && b.length() == 0)
+ return null;
+ else
+ return b.toString();
+ }
+
+ public void run() throws DatabaseException, FileNotFoundException {
+ // Remove the previous database.
+ new File(FileName).delete();
+
+ // Create the database object.
+ // There is no environment for this simple example.
+ DatabaseConfig config = new DatabaseConfig();
+ config.setErrorStream(System.err);
+ config.setErrorPrefix("BulkAccessExample");
+ config.setType(DatabaseType.BTREE);
+ config.setAllowCreate(true);
+ config.setMode(0644);
+ Database table = new Database(FileName, null, config);
+
+ //
+ // Insert records into the database, where the key is the user
+ // input and the data is the user input in reverse order.
+ //
+ InputStreamReader reader = new InputStreamReader(System.in);
+
+ for (;;) {
+ String line = askForLine(reader, System.out, "input> ");
+ if (line == null || (line.compareToIgnoreCase("end") == 0))
+ break;
+
+ String reversed = (new StringBuffer(line)).reverse().toString();
+
+ // See definition of StringEntry below
+ //
+ StringEntry key = new StringEntry(line);
+ StringEntry data = new StringEntry(reversed);
+
+ try {
+ if (table.putNoOverwrite(null, key, data) == OperationStatus.KEYEXIST)
+ System.out.println("Key " + line + " already exists.");
+ } catch (DatabaseException dbe) {
+ System.out.println(dbe.toString());
+ }
+ System.out.println("");
+ }
+
+ // Acquire a cursor for the table.
+ Cursor cursor = table.openCursor(null, null);
+ DatabaseEntry foo = new DatabaseEntry();
+
+ MultipleKeyDataEntry bulk_data = new MultipleKeyDataEntry();
+ bulk_data.setData(new byte[1024 * 1024]);
+ bulk_data.setUserBuffer(1024 * 1024, true);
+
+ // Walk through the table, printing the key/data pairs.
+ //
+ while (cursor.getNext(foo, bulk_data, null) == OperationStatus.SUCCESS) {
+ StringEntry key, data;
+ key = new StringEntry();
+ data = new StringEntry();
+
+ while (bulk_data.next(key, data))
+ System.out.println(key.getString() + " : " + data.getString());
+ }
+ cursor.close();
+ table.close();
+ }
+
+ // Here's an example of how you can extend DatabaseEntry in a
+ // straightforward way to allow easy storage/retrieval of strings, or
+ // whatever kind of data you wish. We've declared it as a static inner
+ // class, but it need not be.
+ //
+ static class StringEntry extends DatabaseEntry {
+ StringEntry() {
+ }
+
+ StringEntry(String value) {
+ setString(value);
+ }
+
+ void setString(String value) {
+ byte[] data = value.getBytes();
+ setData(data);
+ setSize(data.length);
+ }
+
+ String getString() {
+ return new String(getData(), getOffset(), getSize());
+ }
+ }
+}
diff --git a/examples_java/src/db/BulkAccessNIOExample.java b/examples_java/src/db/BulkAccessNIOExample.java
new file mode 100644
index 0000000..9f97c4b
--- /dev/null
+++ b/examples_java/src/db/BulkAccessNIOExample.java
@@ -0,0 +1,180 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 1997-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package db;
+
+import com.sleepycat.db.*;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.InputStreamReader;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.nio.ByteBuffer;
+
+class BulkAccessNIOExample {
+ private static final String FileName = "access.db";
+
+ public BulkAccessNIOExample() {
+ }
+
+ public static void main(String[] argv) {
+ try {
+ BulkAccessNIOExample app = new BulkAccessNIOExample();
+ app.run();
+ } catch (DatabaseException dbe) {
+ System.err.println("BulkAccessNIOExample: " + dbe.toString());
+ System.exit(1);
+ } catch (FileNotFoundException fnfe) {
+ System.err.println("BulkAccessNIOExample: " + fnfe.toString());
+ System.exit(1);
+ }
+ System.exit(0);
+ }
+
+ // Prompts for a line, and keeps prompting until a non blank
+ // line is returned. Returns null on error.
+ //
+ public static String askForLine(InputStreamReader reader,
+ PrintStream out, String prompt) {
+ String result = "";
+ while (result != null && result.length() == 0) {
+ out.print(prompt);
+ out.flush();
+ result = getLine(reader);
+ }
+ return result;
+ }
+
+ // Not terribly efficient, but does the job.
+ // Works for reading a line from stdin or a file.
+ // Returns null on EOF. If EOF appears in the middle
+ // of a line, returns that line, then null on next call.
+ //
+ public static String getLine(InputStreamReader reader) {
+ StringBuffer b = new StringBuffer();
+ int c;
+ try {
+ while ((c = reader.read()) != -1 && c != '\n') {
+ if (c != '\r')
+ b.append((char)c);
+ }
+ } catch (IOException ioe) {
+ c = -1;
+ }
+
+ if (c == -1 && b.length() == 0)
+ return null;
+ else
+ return b.toString();
+ }
+
+ public void run() throws DatabaseException, FileNotFoundException {
+ // Remove the previous database.
+ new File(FileName).delete();
+
+ // Create the database object.
+ // There is no environment for this simple example.
+ DatabaseConfig config = new DatabaseConfig();
+ config.setErrorStream(System.err);
+ config.setErrorPrefix("BulkAccessNIOExample");
+ config.setType(DatabaseType.BTREE);
+ config.setAllowCreate(true);
+ config.setMode(0644);
+ Database table = new Database(FileName, null, config);
+
+ //
+ // Insert records into the database, where the key is the user
+ // input and the data is the user input in reverse order.
+ //
+ InputStreamReader reader = new InputStreamReader(System.in);
+
+ for (;;) {
+ String line = askForLine(reader, System.out, "input> ");
+ if (line == null || (line.compareToIgnoreCase("end") == 0))
+ break;
+
+ String reversed = (new StringBuffer(line)).reverse().toString();
+
+ // See definition of StringEntry below
+ //
+ StringEntry key = new StringEntry(line, true);
+ StringEntry data = new StringEntry(reversed, true);
+
+ try {
+ if (table.putNoOverwrite(null, key, data) == OperationStatus.KEYEXIST)
+ System.out.println("Key " + line + " already exists.");
+ } catch (DatabaseException dbe) {
+ System.out.println(dbe.toString());
+ }
+ }
+
+ // Acquire a cursor for the table.
+ Cursor cursor = table.openCursor(null, null);
+ DatabaseEntry foo = new DatabaseEntry();
+
+ MultipleKeyNIODataEntry bulk_data = new MultipleKeyNIODataEntry();
+
+ ByteBuffer rawData = ByteBuffer.allocateDirect(1024*1024);
+ bulk_data.setDataNIO(rawData);
+ bulk_data.setUserBuffer(1024 * 1024, true);
+
+ // Walk through the table, printing the key/data pairs.
+ //
+ while (cursor.getNext(foo, bulk_data, null) == OperationStatus.SUCCESS) {
+ StringEntry key, data;
+ key = new StringEntry();
+ data = new StringEntry();
+
+ while (bulk_data.next(key, data))
+ System.out.println(key.getString() + " : " + data.getString());
+ }
+ cursor.close();
+ table.close();
+ }
+
+ // Here's an example of how you can extend DatabaseEntry in a
+ // straightforward way to allow easy storage/retrieval of strings, or
+ // whatever kind of data you wish. We've declared it as a static inner
+ // class, but it need not be.
+ //
+ static class StringEntry extends DatabaseEntry {
+ StringEntry() {
+ }
+
+ StringEntry(String value, boolean nioData) {
+ setString(value, nioData);
+ }
+
+ void setString(String value, boolean nioData) {
+ byte[] data = value.getBytes();
+ if(nioData) {
+ ByteBuffer newBuf = ByteBuffer.allocateDirect(data.length);
+ newBuf.position(0);
+ newBuf.put(data, 0, data.length);
+ newBuf.position(0);
+ setDataNIO(newBuf);
+ } else {
+ setData(data);
+ }
+ }
+
+ String getString() {
+ String ret;
+ if(getData() == null) {
+ ByteBuffer tmp = getDataNIO();
+ tmp.position(getOffset());
+ byte[] data = new byte[getSize()];
+ tmp.get(data, 0, getSize());
+ ret = new String(data, 0, getSize());
+ } else {
+ ret = new String(getData(), getOffset(), getSize());
+ }
+ return ret;
+ }
+ }
+}
diff --git a/examples_java/src/db/EnvExample.java b/examples_java/src/db/EnvExample.java
new file mode 100644
index 0000000..a8c1f75
--- /dev/null
+++ b/examples_java/src/db/EnvExample.java
@@ -0,0 +1,144 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 1997-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package db;
+
+import com.sleepycat.db.*;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.OutputStream;
+
+/*
+ * An example of a program configuring a database environment.
+ *
+ * For comparison purposes, this example uses a similar structure
+ * as examples/ex_env.c and examples_cxx/EnvExample.cpp.
+ */
+public class EnvExample {
+ private static final String progname = "EnvExample";
+
+ private static void runApplication(Environment dbenv)
+ throws DatabaseException, FileNotFoundException {
+
+ // Open a database in the environment to verify the data_dir
+ // has been set correctly.
+ DatabaseConfig dbconfig = new DatabaseConfig();
+
+ // The database is DB_BTREE.
+ dbconfig.setAllowCreate(true);
+ dbconfig.setMode(0644);
+ dbconfig.setType(DatabaseType.BTREE);
+ Database db=dbenv.openDatabase(null,
+ "jEnvExample_db1.db", null, dbconfig);
+
+ // Close the database.
+ db.close();
+ }
+
+ private static void setupEnvironment(File home,
+ File dataDir,
+ OutputStream errs)
+ throws DatabaseException, FileNotFoundException {
+
+ // Create an environment object and initialize it for error reporting.
+ EnvironmentConfig config = new EnvironmentConfig();
+ config.setErrorStream(errs);
+ config.setErrorPrefix(progname);
+
+ //
+ // We want to specify the shared memory buffer pool cachesize,
+ // but everything else is the default.
+ //
+ config.setCacheSize(64 * 1024);
+
+ // Databases are in a separate directory.
+ config.addDataDir(dataDir);
+
+ // Open the environment with full transactional support.
+ config.setAllowCreate(true);
+ config.setInitializeCache(true);
+ config.setTransactional(true);
+ config.setInitializeLocking(true);
+
+ //
+ // open is declared to throw a FileNotFoundException, which normally
+ // shouldn't occur when allowCreate is set.
+ //
+ Environment dbenv = new Environment(home, config);
+
+ try {
+ // Start your application.
+ runApplication(dbenv);
+ } finally {
+ // Close the environment. Doing this in the finally block ensures
+ // it is done, even if an error is thrown.
+ dbenv.close();
+ }
+ }
+
+ private static void teardownEnvironment(File home,
+ File dataDir,
+ OutputStream errs)
+ throws DatabaseException, FileNotFoundException {
+
+ // Remove the shared database regions.
+ EnvironmentConfig config = new EnvironmentConfig();
+
+ config.setErrorStream(errs);
+ config.setErrorPrefix(progname);
+ config.addDataDir(dataDir);
+ Environment.remove(home, true, config);
+ }
+
+ private static void usage() {
+ System.err.println("usage: java db.EnvExample [-h home] [-d data_dir]");
+ System.exit(1);
+ }
+
+ public static void main(String[] argv) {
+ //
+ // All of the shared database files live in home,
+ // but data files live in dataDir.
+ //
+ // Using Berkeley DB in C/C++, we need to allocate two elements
+ // in the array and set config[1] to NULL. This is not
+ // necessary in Java.
+ //
+ File home = new File("TESTDIR");
+ File dataDir = new File("data");
+
+ for (int i = 0; i < argv.length; ++i) {
+ if (argv[i].equals("-h")) {
+ if (++i >= argv.length)
+ usage();
+ home = new File(argv[i]);
+ } else if (argv[i].equals("-d")) {
+ if (++i >= argv.length)
+ usage();
+ dataDir = new File(argv[i]);
+ } else if (argv[i].equals("-u")) {
+ usage();
+ }
+ }
+
+ try {
+ System.out.println("Setup env");
+ setupEnvironment(home, dataDir, System.err);
+
+ System.out.println("Teardown env");
+ teardownEnvironment(home, dataDir, System.err);
+ } catch (DatabaseException dbe) {
+ System.err.println(progname + ": environment open: " + dbe.toString());
+ System.exit (1);
+ } catch (FileNotFoundException fnfe) {
+ System.err.println(progname + ": unexpected open environment error " + fnfe);
+ System.exit (1);
+ }
+ }
+
+}
diff --git a/examples_java/src/db/GettingStarted/ExampleDatabaseLoad.java b/examples_java/src/db/GettingStarted/ExampleDatabaseLoad.java
new file mode 100644
index 0000000..8346f6d
--- /dev/null
+++ b/examples_java/src/db/GettingStarted/ExampleDatabaseLoad.java
@@ -0,0 +1,231 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2004-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+// File: ExampleDatabaseLoad.java
+
+package db.GettingStarted;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.StringTokenizer;
+import java.util.Vector;
+
+import com.sleepycat.bind.EntryBinding;
+import com.sleepycat.bind.serial.SerialBinding;
+import com.sleepycat.bind.tuple.TupleBinding;
+import com.sleepycat.db.DatabaseEntry;
+import com.sleepycat.db.DatabaseException;
+
+public class ExampleDatabaseLoad {
+
+ private static String myDbsPath = "./";
+ private static File inventoryFile = new File("./inventory.txt");
+ private static File vendorsFile = new File("./vendors.txt");
+
+ // DatabaseEntries used for loading records
+ private static DatabaseEntry theKey = new DatabaseEntry();
+ private static DatabaseEntry theData = new DatabaseEntry();
+
+ // Encapsulates the databases.
+ private static MyDbs myDbs = new MyDbs();
+
+ private static void usage() {
+ System.out.println("ExampleDatabaseLoad [-h <database home>]");
+ System.out.println(" [-i <inventory file>] [-v <vendors file>]");
+ System.exit(-1);
+ }
+
+
+ public static void main(String args[]) {
+ ExampleDatabaseLoad edl = new ExampleDatabaseLoad();
+ try {
+ edl.run(args);
+ } catch (DatabaseException dbe) {
+ System.err.println("ExampleDatabaseLoad: " + dbe.toString());
+ dbe.printStackTrace();
+ } catch (Exception e) {
+ System.out.println("Exception: " + e.toString());
+ e.printStackTrace();
+ } finally {
+ myDbs.close();
+ }
+ System.out.println("All done.");
+ }
+
+
+ private void run(String args[])
+ throws DatabaseException {
+ // Parse the arguments list
+ parseArgs(args);
+
+ myDbs.setup(myDbsPath);
+
+ System.out.println("loading vendors db....");
+ loadVendorsDb();
+
+ System.out.println("loading inventory db....");
+ loadInventoryDb();
+ }
+
+
+ private void loadVendorsDb()
+ throws DatabaseException {
+
+ // loadFile opens a flat-text file that contains our data
+ // and loads it into a list for us to work with. The integer
+ // parameter represents the number of fields expected in the
+ // file.
+ List vendors = loadFile(vendorsFile, 8);
+
+ // Now load the data into the database. The vendor's name is the
+ // key, and the data is a Vendor class object.
+
+ // Need a serial binding for the data
+ EntryBinding dataBinding =
+ new SerialBinding(myDbs.getClassCatalog(), Vendor.class);
+
+ for (int i = 0; i < vendors.size(); i++) {
+ String[] sArray = (String[])vendors.get(i);
+ Vendor theVendor = new Vendor();
+ theVendor.setVendorName(sArray[0]);
+ theVendor.setAddress(sArray[1]);
+ theVendor.setCity(sArray[2]);
+ theVendor.setState(sArray[3]);
+ theVendor.setZipcode(sArray[4]);
+ theVendor.setBusinessPhoneNumber(sArray[5]);
+ theVendor.setRepName(sArray[6]);
+ theVendor.setRepPhoneNumber(sArray[7]);
+
+ // The key is the vendor's name.
+ // ASSUMES THE VENDOR'S NAME IS UNIQUE!
+ String vendorName = theVendor.getVendorName();
+ try {
+ theKey = new DatabaseEntry(vendorName.getBytes("UTF-8"));
+ } catch (IOException willNeverOccur) {}
+
+ // Convert the Vendor object to a DatabaseEntry object
+ // using our SerialBinding
+ dataBinding.objectToEntry(theVendor, theData);
+
+ // Put it in the database.
+ myDbs.getVendorDB().put(null, theKey, theData);
+ }
+ }
+
+
+ private void loadInventoryDb()
+ throws DatabaseException {
+
+ // loadFile opens a flat-text file that contains our data
+ // and loads it into a list for us to work with. The integer
+ // parameter represents the number of fields expected in the
+ // file.
+ List inventoryArray = loadFile(inventoryFile, 6);
+
+ // Now load the data into the database. The item's sku is the
+ // key, and the data is an Inventory class object.
+
+ // Need a tuple binding for the Inventory class.
+ TupleBinding inventoryBinding = new InventoryBinding();
+
+ for (int i = 0; i < inventoryArray.size(); i++) {
+ String[] sArray = (String[])inventoryArray.get(i);
+ String sku = sArray[1];
+ try {
+ theKey = new DatabaseEntry(sku.getBytes("UTF-8"));
+ } catch (IOException willNeverOccur) {}
+
+ Inventory theInventory = new Inventory();
+ theInventory.setItemName(sArray[0]);
+ theInventory.setSku(sArray[1]);
+ theInventory.setVendorPrice((new Float(sArray[2])).floatValue());
+ theInventory.setVendorInventory((new Integer(sArray[3])).intValue());
+ theInventory.setCategory(sArray[4]);
+ theInventory.setVendor(sArray[5]);
+
+ // Place the Vendor object on the DatabaseEntry object using our
+ // the tuple binding we implemented in InventoryBinding.java
+ inventoryBinding.objectToEntry(theInventory, theData);
+
+ // Put it in the database. Note that this causes our secondary database
+ // to be automatically updated for us.
+ myDbs.getInventoryDB().put(null, theKey, theData);
+ }
+ }
+
+
+ private static void parseArgs(String args[]) {
+ for(int i = 0; i < args.length; ++i) {
+ if (args[i].startsWith("-")) {
+ switch(args[i].charAt(1)) {
+ case 'h':
+ myDbsPath = new String(args[++i]);
+ break;
+ case 'i':
+ inventoryFile = new File(args[++i]);
+ break;
+ case 'v':
+ vendorsFile = new File(args[++i]);
+ break;
+ default:
+ usage();
+ }
+ }
+ }
+ }
+
+
+ private List loadFile(File theFile, int numFields) {
+ List records = new ArrayList();
+ try {
+ String theLine = null;
+ FileInputStream fis = new FileInputStream(theFile);
+ BufferedReader br = new BufferedReader(new InputStreamReader(fis));
+ while((theLine=br.readLine()) != null) {
+ String[] theLineArray = splitString(theLine, "#");
+ if (theLineArray.length != numFields) {
+ System.out.println("Malformed line found in " + theFile.getPath());
+ System.out.println("Line was: '" + theLine);
+ System.out.println("length found was: " + theLineArray.length);
+ System.exit(-1);
+ }
+ records.add(theLineArray);
+ }
+ fis.close();
+ } catch (FileNotFoundException e) {
+ System.err.println(theFile.getPath() + " does not exist.");
+ e.printStackTrace();
+ usage();
+ } catch (IOException e) {
+ System.err.println("IO Exception: " + e.toString());
+ e.printStackTrace();
+ System.exit(-1);
+ }
+ return records;
+ }
+
+
+ private static String[] splitString(String s, String delimiter) {
+ Vector resultVector = new Vector();
+ StringTokenizer tokenizer = new StringTokenizer(s, delimiter);
+ while (tokenizer.hasMoreTokens())
+ resultVector.add(tokenizer.nextToken());
+ String[] resultArray = new String[resultVector.size()];
+ resultVector.copyInto(resultArray);
+ return resultArray;
+ }
+
+
+ protected ExampleDatabaseLoad() {}
+}
diff --git a/examples_java/src/db/GettingStarted/ExampleDatabaseRead.java b/examples_java/src/db/GettingStarted/ExampleDatabaseRead.java
new file mode 100644
index 0000000..dbaab60
--- /dev/null
+++ b/examples_java/src/db/GettingStarted/ExampleDatabaseRead.java
@@ -0,0 +1,205 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2004-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+// File: ExampleDatabaseRead
+
+package db.GettingStarted;
+
+import com.sleepycat.bind.EntryBinding;
+import com.sleepycat.bind.serial.SerialBinding;
+import com.sleepycat.bind.tuple.TupleBinding;
+import com.sleepycat.db.Cursor;
+import com.sleepycat.db.DatabaseEntry;
+import com.sleepycat.db.DatabaseException;
+import com.sleepycat.db.LockMode;
+import com.sleepycat.db.OperationStatus;
+import com.sleepycat.db.SecondaryCursor;
+
+import java.io.IOException;
+
+public class ExampleDatabaseRead {
+
+ private static String myDbsPath = "./";
+
+ // Encapsulates the database environment and databases.
+ private static MyDbs myDbs = new MyDbs();
+
+ private static TupleBinding inventoryBinding;
+ private static EntryBinding vendorBinding;
+
+ // The item to locate if the -s switch is used
+ private static String locateItem;
+
+ private static void usage() {
+ System.out.println("ExampleDatabaseRead [-h <env directory>]" +
+ "[-s <item to locate>]");
+ System.exit(-1);
+ }
+
+ public static void main(String args[]) {
+ ExampleDatabaseRead edr = new ExampleDatabaseRead();
+ try {
+ edr.run(args);
+ } catch (DatabaseException dbe) {
+ System.err.println("ExampleDatabaseRead: " + dbe.toString());
+ dbe.printStackTrace();
+ } finally {
+ myDbs.close();
+ }
+ System.out.println("All done.");
+ }
+
+ private void run(String args[])
+ throws DatabaseException {
+ // Parse the arguments list
+ parseArgs(args);
+
+ myDbs.setup(myDbsPath);
+
+ // Setup our bindings.
+ inventoryBinding = new InventoryBinding();
+ vendorBinding =
+ new SerialBinding(myDbs.getClassCatalog(),
+ Vendor.class);
+
+ if (locateItem != null) {
+ showItem();
+ } else {
+ showAllInventory();
+ }
+ }
+
+ private void showItem() throws DatabaseException {
+
+ SecondaryCursor secCursor = null;
+ try {
+ // searchKey is the key that we want to find in the
+ // secondary db.
+ DatabaseEntry searchKey =
+ new DatabaseEntry(locateItem.getBytes("UTF-8"));
+
+ // foundKey and foundData are populated from the primary
+ // entry that is associated with the secondary db key.
+ DatabaseEntry foundKey = new DatabaseEntry();
+ DatabaseEntry foundData = new DatabaseEntry();
+
+ // open a secondary cursor
+ secCursor =
+ myDbs.getNameIndexDB().openSecondaryCursor(null, null);
+
+ // Search for the secondary database entry.
+ OperationStatus retVal =
+ secCursor.getSearchKey(searchKey, foundKey,
+ foundData, LockMode.DEFAULT);
+
+ // Display the entry, if one is found. Repeat until no more
+ // secondary duplicate entries are found
+ while(retVal == OperationStatus.SUCCESS) {
+ Inventory theInventory =
+ (Inventory)inventoryBinding.entryToObject(foundData);
+ displayInventoryRecord(foundKey, theInventory);
+ retVal = secCursor.getNextDup(searchKey, foundKey,
+ foundData, LockMode.DEFAULT);
+ }
+ } catch (Exception e) {
+ System.err.println("Error on inventory secondary cursor:");
+ System.err.println(e.toString());
+ e.printStackTrace();
+ } finally {
+ if (secCursor != null) {
+ secCursor.close();
+ }
+ }
+ }
+
+ private void showAllInventory()
+ throws DatabaseException {
+ // Get a cursor
+ Cursor cursor = myDbs.getInventoryDB().openCursor(null, null);
+
+ // DatabaseEntry objects used for reading records
+ DatabaseEntry foundKey = new DatabaseEntry();
+ DatabaseEntry foundData = new DatabaseEntry();
+
+ try { // always want to make sure the cursor gets closed
+ while (cursor.getNext(foundKey, foundData,
+ LockMode.DEFAULT) == OperationStatus.SUCCESS) {
+ Inventory theInventory =
+ (Inventory)inventoryBinding.entryToObject(foundData);
+ displayInventoryRecord(foundKey, theInventory);
+ }
+ } catch (Exception e) {
+ System.err.println("Error on inventory cursor:");
+ System.err.println(e.toString());
+ e.printStackTrace();
+ } finally {
+ cursor.close();
+ }
+ }
+
+ private void displayInventoryRecord(DatabaseEntry theKey,
+ Inventory theInventory)
+ throws DatabaseException {
+
+ String theSKU = new String(theKey.getData());
+ System.out.println(theSKU + ":");
+ System.out.println("\t " + theInventory.getItemName());
+ System.out.println("\t " + theInventory.getCategory());
+ System.out.println("\t " + theInventory.getVendor());
+ System.out.println("\t\tNumber in stock: " +
+ theInventory.getVendorInventory());
+ System.out.println("\t\tPrice per unit: " +
+ theInventory.getVendorPrice());
+ System.out.println("\t\tContact: ");
+
+ DatabaseEntry searchKey = null;
+ try {
+ searchKey =
+ new DatabaseEntry(theInventory.getVendor().getBytes("UTF-8"));
+ } catch (IOException willNeverOccur) {}
+ DatabaseEntry foundVendor = new DatabaseEntry();
+
+ if (myDbs.getVendorDB().get(null, searchKey, foundVendor,
+ LockMode.DEFAULT) != OperationStatus.SUCCESS) {
+ System.out.println("Could not find vendor: " +
+ theInventory.getVendor() + ".");
+ System.exit(-1);
+ } else {
+ Vendor theVendor =
+ (Vendor)vendorBinding.entryToObject(foundVendor);
+ System.out.println("\t\t " + theVendor.getAddress());
+ System.out.println("\t\t " + theVendor.getCity() + ", " +
+ theVendor.getState() + " " + theVendor.getZipcode());
+ System.out.println("\t\t Business Phone: " +
+ theVendor.getBusinessPhoneNumber());
+ System.out.println("\t\t Sales Rep: " +
+ theVendor.getRepName());
+ System.out.println("\t\t " +
+ theVendor.getRepPhoneNumber());
+ }
+ }
+
+ protected ExampleDatabaseRead() {}
+
+ private static void parseArgs(String args[]) {
+ for(int i = 0; i < args.length; ++i) {
+ if (args[i].startsWith("-")) {
+ switch(args[i].charAt(1)) {
+ case 'h':
+ myDbsPath = new String(args[++i]);
+ break;
+ case 's':
+ locateItem = new String(args[++i]);
+ break;
+ default:
+ usage();
+ }
+ }
+ }
+ }
+}
diff --git a/examples_java/src/db/GettingStarted/Inventory.java b/examples_java/src/db/GettingStarted/Inventory.java
new file mode 100644
index 0000000..d10c5d5
--- /dev/null
+++ b/examples_java/src/db/GettingStarted/Inventory.java
@@ -0,0 +1,70 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2004-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+// File: Inventory.java
+
+package db.GettingStarted;
+
+public class Inventory {
+
+ private String sku;
+ private String itemName;
+ private String category;
+ private String vendor;
+ private int vendorInventory;
+ private float vendorPrice;
+
+ public void setSku(String data) {
+ sku = data;
+ }
+
+ public void setItemName(String data) {
+ itemName = data;
+ }
+
+ public void setCategory(String data) {
+ category = data;
+ }
+
+ public void setVendorInventory(int data) {
+ vendorInventory = data;
+ }
+
+ public void setVendor(String data) {
+ vendor = data;
+ }
+
+ public void setVendorPrice(float data) {
+ vendorPrice = data;
+ }
+
+ public String getSku() {
+ return sku;
+ }
+
+ public String getItemName() {
+ return itemName;
+ }
+
+ public String getCategory() {
+ return category;
+ }
+
+ public int getVendorInventory() {
+ return vendorInventory;
+ }
+
+ public String getVendor() {
+ return vendor;
+ }
+
+ public float getVendorPrice() {
+ return vendorPrice;
+ }
+}
+
diff --git a/examples_java/src/db/GettingStarted/InventoryBinding.java b/examples_java/src/db/GettingStarted/InventoryBinding.java
new file mode 100644
index 0000000..5b1f451
--- /dev/null
+++ b/examples_java/src/db/GettingStarted/InventoryBinding.java
@@ -0,0 +1,54 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2004-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+// File: InventoryBinding.java
+
+package db.GettingStarted;
+
+import com.sleepycat.bind.tuple.TupleBinding;
+import com.sleepycat.bind.tuple.TupleInput;
+import com.sleepycat.bind.tuple.TupleOutput;
+
+public class InventoryBinding extends TupleBinding {
+
+ // Implement this abstract method. Used to convert
+ // a DatabaseEntry to an Inventory object.
+ public Object entryToObject(TupleInput ti) {
+
+ String sku = ti.readString();
+ String itemName = ti.readString();
+ String category = ti.readString();
+ String vendor = ti.readString();
+ int vendorInventory = ti.readInt();
+ float vendorPrice = ti.readFloat();
+
+ Inventory inventory = new Inventory();
+ inventory.setSku(sku);
+ inventory.setItemName(itemName);
+ inventory.setCategory(category);
+ inventory.setVendor(vendor);
+ inventory.setVendorInventory(vendorInventory);
+ inventory.setVendorPrice(vendorPrice);
+
+ return inventory;
+ }
+
+ // Implement this abstract method. Used to convert a
+ // Inventory object to a DatabaseEntry object.
+ public void objectToEntry(Object object, TupleOutput to) {
+
+ Inventory inventory = (Inventory)object;
+
+ to.writeString(inventory.getSku());
+ to.writeString(inventory.getItemName());
+ to.writeString(inventory.getCategory());
+ to.writeString(inventory.getVendor());
+ to.writeInt(inventory.getVendorInventory());
+ to.writeFloat(inventory.getVendorPrice());
+ }
+}
diff --git a/examples_java/src/db/GettingStarted/ItemNameKeyCreator.java b/examples_java/src/db/GettingStarted/ItemNameKeyCreator.java
new file mode 100644
index 0000000..f52834d
--- /dev/null
+++ b/examples_java/src/db/GettingStarted/ItemNameKeyCreator.java
@@ -0,0 +1,45 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2004-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+// File: ItemNameKeyCreator.java
+
+package db.GettingStarted;
+
+import com.sleepycat.bind.tuple.TupleBinding;
+import com.sleepycat.db.SecondaryKeyCreator;
+import com.sleepycat.db.DatabaseEntry;
+import com.sleepycat.db.DatabaseException;
+import com.sleepycat.db.SecondaryDatabase;
+
+public class ItemNameKeyCreator implements SecondaryKeyCreator {
+
+ private TupleBinding theBinding;
+
+ // Use the constructor to set the tuple binding
+ ItemNameKeyCreator(TupleBinding binding) {
+ theBinding = binding;
+ }
+
+ // Abstract method that we must implement
+ public boolean createSecondaryKey(SecondaryDatabase secDb,
+ DatabaseEntry keyEntry, // From the primary
+ DatabaseEntry dataEntry, // From the primary
+ DatabaseEntry resultEntry) // set the key data on this.
+ throws DatabaseException {
+
+ if (dataEntry != null) {
+ // Convert dataEntry to an Inventory object
+ Inventory inventoryItem =
+ (Inventory)theBinding.entryToObject(dataEntry);
+ // Get the item name and use that as the key
+ String theItem = inventoryItem.getItemName();
+ resultEntry.setData(theItem.getBytes());
+ }
+ return true;
+ }
+}
diff --git a/examples_java/src/db/GettingStarted/MyDbs.java b/examples_java/src/db/GettingStarted/MyDbs.java
new file mode 100644
index 0000000..6c35a06
--- /dev/null
+++ b/examples_java/src/db/GettingStarted/MyDbs.java
@@ -0,0 +1,165 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2004-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+// File: MyDbs.java
+
+package db.GettingStarted;
+
+import java.io.FileNotFoundException;
+
+import com.sleepycat.bind.serial.StoredClassCatalog;
+import com.sleepycat.bind.tuple.TupleBinding;
+import com.sleepycat.db.Database;
+import com.sleepycat.db.DatabaseConfig;
+import com.sleepycat.db.DatabaseException;
+import com.sleepycat.db.DatabaseType;
+import com.sleepycat.db.SecondaryConfig;
+import com.sleepycat.db.SecondaryDatabase;
+
+
+public class MyDbs {
+
+ // The databases that our application uses
+ private Database vendorDb = null;
+ private Database inventoryDb = null;
+ private Database classCatalogDb = null;
+ private SecondaryDatabase itemNameIndexDb = null;
+
+ private String vendordb = "VendorDB.db";
+ private String inventorydb = "InventoryDB.db";
+ private String classcatalogdb = "ClassCatalogDB.db";
+ private String itemnameindexdb = "ItemNameIndexDB.db";
+
+ // Needed for object serialization
+ private StoredClassCatalog classCatalog;
+
+ // Our constructor does nothing
+ public MyDbs() {}
+
+ // The setup() method opens all our databases
+ // for us.
+ public void setup(String databasesHome)
+ throws DatabaseException {
+
+ DatabaseConfig myDbConfig = new DatabaseConfig();
+ SecondaryConfig mySecConfig = new SecondaryConfig();
+
+ myDbConfig.setErrorStream(System.err);
+ mySecConfig.setErrorStream(System.err);
+ myDbConfig.setErrorPrefix("MyDbs");
+ mySecConfig.setErrorPrefix("MyDbs");
+ myDbConfig.setType(DatabaseType.BTREE);
+ mySecConfig.setType(DatabaseType.BTREE);
+ myDbConfig.setAllowCreate(true);
+ mySecConfig.setAllowCreate(true);
+
+ // Now open, or create and open, our databases
+ // Open the vendors and inventory databases
+ try {
+ vendordb = databasesHome + "/" + vendordb;
+ vendorDb = new Database(vendordb,
+ null,
+ myDbConfig);
+
+ inventorydb = databasesHome + "/" + inventorydb;
+ inventoryDb = new Database(inventorydb,
+ null,
+ myDbConfig);
+
+ // Open the class catalog db. This is used to
+ // optimize class serialization.
+ classcatalogdb = databasesHome + "/" + classcatalogdb;
+ classCatalogDb = new Database(classcatalogdb,
+ null,
+ myDbConfig);
+ } catch(FileNotFoundException fnfe) {
+ System.err.println("MyDbs: " + fnfe.toString());
+ System.exit(-1);
+ }
+
+ // Create our class catalog
+ classCatalog = new StoredClassCatalog(classCatalogDb);
+
+ // Need a tuple binding for the Inventory class.
+ // We use the InventoryBinding class
+ // that we implemented for this purpose.
+ TupleBinding inventoryBinding = new InventoryBinding();
+
+ // Open the secondary database. We use this to create a
+ // secondary index for the inventory database
+
+ // We want to maintain an index for the inventory entries based
+ // on the item name. So, instantiate the appropriate key creator
+ // and open a secondary database.
+ ItemNameKeyCreator keyCreator =
+ new ItemNameKeyCreator(new InventoryBinding());
+
+
+ // Set up additional secondary properties
+ // Need to allow duplicates for our secondary database
+ mySecConfig.setSortedDuplicates(true);
+ mySecConfig.setAllowPopulate(true); // Allow autopopulate
+ mySecConfig.setKeyCreator(keyCreator);
+
+ // Now open it
+ try {
+ itemnameindexdb = databasesHome + "/" + itemnameindexdb;
+ itemNameIndexDb = new SecondaryDatabase(itemnameindexdb,
+ null,
+ inventoryDb,
+ mySecConfig);
+ } catch(FileNotFoundException fnfe) {
+ System.err.println("MyDbs: " + fnfe.toString());
+ System.exit(-1);
+ }
+ }
+
+ // getter methods
+ public Database getVendorDB() {
+ return vendorDb;
+ }
+
+ public Database getInventoryDB() {
+ return inventoryDb;
+ }
+
+ public SecondaryDatabase getNameIndexDB() {
+ return itemNameIndexDb;
+ }
+
+ public StoredClassCatalog getClassCatalog() {
+ return classCatalog;
+ }
+
+ // Close the databases
+ public void close() {
+ try {
+ if (itemNameIndexDb != null) {
+ itemNameIndexDb.close();
+ }
+
+ if (vendorDb != null) {
+ vendorDb.close();
+ }
+
+ if (inventoryDb != null) {
+ inventoryDb.close();
+ }
+
+ if (classCatalogDb != null) {
+ classCatalogDb.close();
+ }
+
+ } catch(DatabaseException dbe) {
+ System.err.println("Error closing MyDbs: " +
+ dbe.toString());
+ System.exit(-1);
+ }
+ }
+}
+
diff --git a/examples_java/src/db/GettingStarted/Vendor.java b/examples_java/src/db/GettingStarted/Vendor.java
new file mode 100644
index 0000000..4e13ddb
--- /dev/null
+++ b/examples_java/src/db/GettingStarted/Vendor.java
@@ -0,0 +1,90 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2004-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+// File: Vendor.java
+package db.GettingStarted;
+
+import java.io.Serializable;
+
+public class Vendor implements Serializable {
+
+ private String repName;
+ private String address;
+ private String city;
+ private String state;
+ private String zipcode;
+ private String bizPhoneNumber;
+ private String repPhoneNumber;
+ private String vendor;
+
+ public void setRepName(String data) {
+ repName = data;
+ }
+
+ public void setAddress(String data) {
+ address = data;
+ }
+
+ public void setCity(String data) {
+ city = data;
+ }
+
+ public void setState(String data) {
+ state = data;
+ }
+
+ public void setZipcode(String data) {
+ zipcode = data;
+ }
+
+ public void setBusinessPhoneNumber(String data) {
+ bizPhoneNumber = data;
+ }
+
+ public void setRepPhoneNumber(String data) {
+ repPhoneNumber = data;
+ }
+
+ public void setVendorName(String data) {
+ vendor = data;
+ }
+
+ public String getRepName() {
+ return repName;
+ }
+
+ public String getAddress() {
+ return address;
+ }
+
+ public String getCity() {
+ return city;
+ }
+
+ public String getState() {
+ return state;
+ }
+
+ public String getZipcode() {
+ return zipcode;
+ }
+
+ public String getBusinessPhoneNumber() {
+ return bizPhoneNumber;
+ }
+
+ public String getRepPhoneNumber() {
+ return repPhoneNumber;
+ }
+
+ public String getVendorName() {
+ return vendor;
+ }
+
+}
+
diff --git a/examples_java/src/db/GettingStarted/inventory.txt b/examples_java/src/db/GettingStarted/inventory.txt
new file mode 100644
index 0000000..d6b6876
--- /dev/null
+++ b/examples_java/src/db/GettingStarted/inventory.txt
@@ -0,0 +1,800 @@
+Oranges#OranfruiRu6Ghr#0.71#451#fruits#TriCounty Produce
+Oranges#OranfruiXRPFn1#0.73#263#fruits#Simply Fresh
+Oranges#OranfruiLEuzQj#0.69#261#fruits#Off the Vine
+Apples#ApplfruiZls4Du#1.20#472#fruits#TriCounty Produce
+Apples#Applfrui8fewZe#1.21#402#fruits#Simply Fresh
+Apples#ApplfruiXoT6xG#1.20#728#fruits#Off the Vine
+Bananas#BanafruipIlluX#0.50#207#fruits#TriCounty Produce
+Bananas#BanafruiEQhWuj#0.50#518#fruits#Simply Fresh
+Bananas#BanafruimpRgPO#0.50#741#fruits#Off the Vine
+Almonds#AlmofruiPPCLz8#0.55#600#fruits#TriCounty Produce
+Almonds#AlmofruidMyKmp#0.54#745#fruits#Simply Fresh
+Almonds#Almofrui7K0xzH#0.53#405#fruits#Off the Vine
+Allspice#AllsfruibJGK4R#0.94#669#fruits#TriCounty Produce
+Allspice#Allsfruilfvoeg#0.94#244#fruits#Simply Fresh
+Allspice#Allsfruio12BOS#0.95#739#fruits#Off the Vine
+Apricot#AprifruijphEpM#0.89#560#fruits#TriCounty Produce
+Apricot#AprifruiU1zIDn#0.91#980#fruits#Simply Fresh
+Apricot#AprifruichcwYS#0.95#668#fruits#Off the Vine
+Avocado#AvocfruiwYYomu#0.99#379#fruits#TriCounty Produce
+Avocado#AvocfruiT6IwWE#1.02#711#fruits#Simply Fresh
+Avocado#AvocfruisbK1h5#0.97#856#fruits#Off the Vine
+Bael Fruit#BaelfruilAU7Hj#0.41#833#fruits#TriCounty Produce
+Bael Fruit#BaelfruiX2KvqV#0.40#770#fruits#Simply Fresh
+Bael Fruit#Baelfruidjne4e#0.39#778#fruits#Off the Vine
+Betel Nut#BetefruiQYdHqQ#0.34#926#fruits#TriCounty Produce
+Betel Nut#Betefrui32BKAz#0.37#523#fruits#Simply Fresh
+Betel Nut#BetefruisaWzY4#0.34#510#fruits#Off the Vine
+Black Walnut#BlacfruiXxIuMU#0.57#923#fruits#TriCounty Produce
+Black Walnut#BlacfruiZXgY9t#0.59#312#fruits#Simply Fresh
+Black Walnut#BlacfruikWO0vz#0.60#877#fruits#Off the Vine
+Blueberry#BluefruiCbxb4t#1.02#276#fruits#TriCounty Produce
+Blueberry#BluefruiBuCfgO#1.03#522#fruits#Simply Fresh
+Blueberry#Bluefruixz8MkE#1.01#278#fruits#Off the Vine
+Boysenberry#BoysfruizxyMuz#1.05#239#fruits#TriCounty Produce
+Boysenberry#Boysfrui3hTRQu#1.09#628#fruits#Simply Fresh
+Boysenberry#BoysfruinpLvr3#1.02#349#fruits#Off the Vine
+Breadnut#Breafrui0kDPs6#0.31#558#fruits#TriCounty Produce
+Breadnut#Breafrui44s3og#0.32#879#fruits#Simply Fresh
+Breadnut#BreafruiwyLKhJ#0.30#407#fruits#Off the Vine
+Cactus#Cactfruiyo2ddH#0.56#601#fruits#TriCounty Produce
+Cactus#CactfruixTOLv5#0.54#477#fruits#Simply Fresh
+Cactus#Cactfrui4ioUav#0.55#896#fruits#Off the Vine
+California Wild Grape#CalifruiZsWAa6#0.78#693#fruits#TriCounty Produce
+California Wild Grape#Califruid84xyt#0.83#293#fruits#Simply Fresh
+California Wild Grape#CalifruiLSJFoJ#0.81#543#fruits#Off the Vine
+Cashew#CashfruihaOFVP#0.37#221#fruits#TriCounty Produce
+Cashew#Cashfruizzcw1E#0.38#825#fruits#Simply Fresh
+Cashew#CashfruiqtMe2Q#0.38#515#fruits#Off the Vine
+Chico Sapote#ChicfruiY534SX#0.47#216#fruits#TriCounty Produce
+Chico Sapote#ChicfruiSqL3Lc#0.45#476#fruits#Simply Fresh
+Chico Sapote#ChicfruiurzIp4#0.47#200#fruits#Off the Vine
+Chinese Jello#ChinfruiyRg75u#0.64#772#fruits#TriCounty Produce
+Chinese Jello#ChinfruiuIUj0X#0.65#624#fruits#Simply Fresh
+Chinese Jello#ChinfruiwXbRrL#0.67#719#fruits#Off the Vine
+Common Guava#Commfruib6znSI#0.80#483#fruits#TriCounty Produce
+Common Guava#Commfrui6eUivL#0.81#688#fruits#Simply Fresh
+Common Guava#CommfruibWKnz3#0.84#581#fruits#Off the Vine
+Crabapple#CrabfruioY2L63#0.94#582#fruits#TriCounty Produce
+Crabapple#Crabfruijxcxyt#0.94#278#fruits#Simply Fresh
+Crabapple#CrabfruibvWd8K#0.95#213#fruits#Off the Vine
+Cranberry#CranfruiJxmKr5#0.83#923#fruits#TriCounty Produce
+Cranberry#CranfruiPlklAF#0.84#434#fruits#Simply Fresh
+Cranberry#Cranfrui3G5XL9#0.84#880#fruits#Off the Vine
+Damson Plum#DamsfruibMRMwe#0.98#782#fruits#TriCounty Produce
+Damson Plum#DamsfruiV6wFLk#1.03#400#fruits#Simply Fresh
+Damson Plum#DamsfruiLhqFrQ#0.98#489#fruits#Off the Vine
+Date Palm#DatefruigS31GU#1.14#315#fruits#TriCounty Produce
+Date Palm#DatefruipKPaJK#1.09#588#fruits#Simply Fresh
+Date Palm#Datefrui5fTyNS#1.14#539#fruits#Off the Vine
+Dragon's Eye#DragfruirGJ3aI#0.28#315#fruits#TriCounty Produce
+Dragon's Eye#DragfruiBotxqt#0.27#705#fruits#Simply Fresh
+Dragon's Eye#DragfruiPsSnV9#0.29#482#fruits#Off the Vine
+East Indian Wine Palm#EastfruiNXFJuG#0.43#992#fruits#TriCounty Produce
+East Indian Wine Palm#Eastfruiq06fRr#0.40#990#fruits#Simply Fresh
+East Indian Wine Palm#Eastfrui4QUwl2#0.43#351#fruits#Off the Vine
+English Walnut#EnglfruiBMtHtW#1.04#787#fruits#TriCounty Produce
+English Walnut#EnglfruiHmVzxV#1.03#779#fruits#Simply Fresh
+English Walnut#Englfrui18Tc9n#1.06#339#fruits#Off the Vine
+False Mangosteen#FalsfruibkmYqH#0.66#971#fruits#TriCounty Produce
+False Mangosteen#FalsfruipBsbcX#0.68#250#fruits#Simply Fresh
+False Mangosteen#FalsfruiPrFfhe#0.70#386#fruits#Off the Vine
+Fried Egg Tree#FriefruiihHUdc#0.29#649#fruits#TriCounty Produce
+Fried Egg Tree#FriefruimdD1rf#0.28#527#fruits#Simply Fresh
+Fried Egg Tree#FriefruivyAzYq#0.29#332#fruits#Off the Vine
+Genipap#GenifruiDtKusQ#0.62#986#fruits#TriCounty Produce
+Genipap#GenifruiXq32eP#0.61#326#fruits#Simply Fresh
+Genipap#Genifruiphwwyq#0.61#794#fruits#Off the Vine
+Ginger#GingfruiQLbRZI#0.28#841#fruits#TriCounty Produce
+Ginger#GingfruiS8kK4p#0.29#432#fruits#Simply Fresh
+Ginger#GingfruioL3Y4S#0.27#928#fruits#Off the Vine
+Grapefruit#Grapfruih86Zxh#1.07#473#fruits#TriCounty Produce
+Grapefruit#GrapfruiwL1v0N#1.08#878#fruits#Simply Fresh
+Grapefruit#GrapfruihmJzWm#1.02#466#fruits#Off the Vine
+Hackberry#HackfruiQjomN7#0.22#938#fruits#TriCounty Produce
+Hackberry#HackfruiWS0eKp#0.20#780#fruits#Simply Fresh
+Hackberry#Hackfrui0MIv6J#0.21#345#fruits#Off the Vine
+Honey Locust#HonefruiebXGRc#1.08#298#fruits#TriCounty Produce
+Honey Locust#HonefruiPSqILB#1.00#427#fruits#Simply Fresh
+Honey Locust#Honefrui6UXtvW#1.03#422#fruits#Off the Vine
+Japanese Plum#JapafruihTmoYR#0.40#658#fruits#TriCounty Produce
+Japanese Plum#JapafruifGqz0l#0.40#700#fruits#Simply Fresh
+Japanese Plum#JapafruiufWkLx#0.39#790#fruits#Off the Vine
+Jojoba#JojofruisE0wTh#0.97#553#fruits#TriCounty Produce
+Jojoba#JojofruiwiYLp2#1.02#969#fruits#Simply Fresh
+Jojoba#JojofruigMD1ej#0.96#899#fruits#Off the Vine
+Jostaberry#JostfruiglsEGV#0.50#300#fruits#TriCounty Produce
+Jostaberry#JostfruiV3oo1h#0.52#423#fruits#Simply Fresh
+Jostaberry#JostfruiUBerur#0.53#562#fruits#Off the Vine
+Kangaroo Apple#KangfruiEQknz8#0.60#661#fruits#TriCounty Produce
+Kangaroo Apple#KangfruiNabdFq#0.60#377#fruits#Simply Fresh
+Kangaroo Apple#Kangfrui7hky1i#0.60#326#fruits#Off the Vine
+Ken's Red#Ken'fruinPUSIm#0.21#337#fruits#TriCounty Produce
+Ken's Red#Ken'fruiAoZlpl#0.21#902#fruits#Simply Fresh
+Ken's Red#Ken'frui5rmbd4#0.22#972#fruits#Off the Vine
+Ketembilla#Ketefrui3yAKxQ#0.31#303#fruits#TriCounty Produce
+Ketembilla#KetefruiROn6F5#0.34#283#fruits#Simply Fresh
+Ketembilla#Ketefrui16Rsts#0.33#887#fruits#Off the Vine
+King Orange#KingfruisOFzWk#0.74#429#fruits#TriCounty Produce
+King Orange#KingfruiBmzRJT#0.74#500#fruits#Simply Fresh
+King Orange#KingfruiGsrgRX#0.78#994#fruits#Off the Vine
+Kola Nut#KolafruiBbtAuw#0.58#991#fruits#TriCounty Produce
+Kola Nut#KolafruirbnLVS#0.62#733#fruits#Simply Fresh
+Kola Nut#Kolafrui1ItXJx#0.58#273#fruits#Off the Vine
+Kuko#Kukofrui6YH5Ds#0.41#647#fruits#TriCounty Produce
+Kuko#Kukofrui7WZaZK#0.39#241#fruits#Simply Fresh
+Kuko#Kukofruig9MQFT#0.40#204#fruits#Off the Vine
+Kumquat#KumqfruiT6WKQL#0.73#388#fruits#TriCounty Produce
+Kumquat#KumqfruidLiFLU#0.70#393#fruits#Simply Fresh
+Kumquat#KumqfruiL6zhQX#0.71#994#fruits#Off the Vine
+Kwai Muk#KwaifruiQK1zOE#1.10#249#fruits#TriCounty Produce
+Kwai Muk#KwaifruifbCRlT#1.14#657#fruits#Simply Fresh
+Kwai Muk#Kwaifruipe7T2m#1.09#617#fruits#Off the Vine
+Lanzone#LanzfruijsPf1v#0.34#835#fruits#TriCounty Produce
+Lanzone#LanzfruibU3QoL#0.34#404#fruits#Simply Fresh
+Lanzone#LanzfruiYgHwv6#0.34#237#fruits#Off the Vine
+Lemon#Lemofrui4Tgsg2#0.46#843#fruits#TriCounty Produce
+Lemon#LemofruivK6qvj#0.43#207#fruits#Simply Fresh
+Lemon#LemofruiXSXqJ0#0.44#910#fruits#Off the Vine
+Lemon Grass#LemofruiVFgVh5#0.40#575#fruits#TriCounty Produce
+Lemon Grass#LemofruiWIelvi#0.41#386#fruits#Simply Fresh
+Lemon Grass#LemofruiGVAow0#0.39#918#fruits#Off the Vine
+Lilly-pilly#LillfruiEQnW1m#1.21#974#fruits#TriCounty Produce
+Lilly-pilly#LillfruiMqVuR5#1.23#303#fruits#Simply Fresh
+Lilly-pilly#LillfruiVGH9p4#1.17#512#fruits#Off the Vine
+Ling Nut#LingfruiGtOf8X#0.85#540#fruits#TriCounty Produce
+Ling Nut#LingfruiuP0Jf9#0.83#200#fruits#Simply Fresh
+Ling Nut#LingfruiuO5qf5#0.81#319#fruits#Off the Vine
+Lipote#LipofruisxD2Qc#0.85#249#fruits#TriCounty Produce
+Lipote#LipofruiHNdIqL#0.85#579#fruits#Simply Fresh
+Lipote#LipofruiSQ2pKK#0.83#472#fruits#Off the Vine
+Litchee#Litcfrui1R6Ydz#0.99#806#fruits#TriCounty Produce
+Litchee#LitcfruiwtDM79#1.01#219#fruits#Simply Fresh
+Litchee#LitcfruilpPZbC#1.05#419#fruits#Off the Vine
+Longan#LongfruiEI0lWF#1.02#573#fruits#TriCounty Produce
+Longan#LongfruiPQxxSF#1.04#227#fruits#Simply Fresh
+Longan#LongfruisdI812#0.99#993#fruits#Off the Vine
+Love-in-a-mist#LovefruiKYPW70#0.69#388#fruits#TriCounty Produce
+Love-in-a-mist#LovefruiHrgjDa#0.67#478#fruits#Simply Fresh
+Love-in-a-mist#LovefruipSOWVz#0.71#748#fruits#Off the Vine
+Lychee#LychfruiicVLnY#0.38#276#fruits#TriCounty Produce
+Lychee#LychfruiGY6yJr#0.38#602#fruits#Simply Fresh
+Lychee#LychfruiTzDCq2#0.40#572#fruits#Off the Vine
+Mabolo#MabofruiSY8RQS#0.97#263#fruits#TriCounty Produce
+Mabolo#MabofruiOWWk0n#0.98#729#fruits#Simply Fresh
+Mabolo#MabofruixQLOTF#0.98#771#fruits#Off the Vine
+Macadamia Nut#MacafruiZppJPw#1.22#888#fruits#TriCounty Produce
+Macadamia Nut#MacafruiI7XFMV#1.24#484#fruits#Simply Fresh
+Macadamia Nut#Macafrui4x8bxV#1.20#536#fruits#Off the Vine
+Madagascar Plum#MadafruiVj5fDf#1.14#596#fruits#TriCounty Produce
+Madagascar Plum#MadafruivJhAFI#1.15#807#fruits#Simply Fresh
+Madagascar Plum#Madafrui7MTe1x#1.17#355#fruits#Off the Vine
+Magnolia Vine#MagnfruiigN4Y1#1.17#321#fruits#TriCounty Produce
+Magnolia Vine#MagnfruicKtiHd#1.15#353#fruits#Simply Fresh
+Magnolia Vine#MagnfruiLPDSCp#1.23#324#fruits#Off the Vine
+Mamey#Mamefrui5rjLF6#0.36#683#fruits#TriCounty Produce
+Mamey#MamefruiM6ndnR#0.38#404#fruits#Simply Fresh
+Mamey#Mamefruiq9KntD#0.36#527#fruits#Off the Vine
+Mandarin Orange#MandfruiRKpmKL#0.42#352#fruits#TriCounty Produce
+Mandarin Orange#Mandfrui1V0KLG#0.42#548#fruits#Simply Fresh
+Mandarin Orange#Mandfruig2o9Fg#0.41#686#fruits#Off the Vine
+Marany Nut#MarafruiqkrwoJ#1.14#273#fruits#TriCounty Produce
+Marany Nut#MarafruiCGKpke#1.12#482#fruits#Simply Fresh
+Marany Nut#MarafruiB1YE5x#1.09#412#fruits#Off the Vine
+Marula#MarufruiXF4biH#0.22#403#fruits#TriCounty Produce
+Marula#MarufruidZiVKZ#0.23#317#fruits#Simply Fresh
+Marula#MarufruiIS8BEp#0.21#454#fruits#Off the Vine
+Mayhaw#MayhfruiCSrm7k#0.24#220#fruits#TriCounty Produce
+Mayhaw#MayhfruiNRDzWs#0.25#710#fruits#Simply Fresh
+Mayhaw#MayhfruiIUCyEg#0.24#818#fruits#Off the Vine
+Meiwa Kumquat#MeiwfruiYhv3AY#0.21#997#fruits#TriCounty Produce
+Meiwa Kumquat#MeiwfruiyzQFNR#0.22#347#fruits#Simply Fresh
+Meiwa Kumquat#Meiwfruict4OUp#0.21#923#fruits#Off the Vine
+Mexican Barberry#Mexifrui2P2dXi#0.28#914#fruits#TriCounty Produce
+Mexican Barberry#MexifruiywUTMI#0.29#782#fruits#Simply Fresh
+Mexican Barberry#MexifruijPHu5X#0.29#367#fruits#Off the Vine
+Meyer Lemon#Meyefruin9901J#0.38#824#fruits#TriCounty Produce
+Meyer Lemon#MeyefruiNeQpjO#0.37#617#fruits#Simply Fresh
+Meyer Lemon#MeyefruiYEVznZ#0.37#741#fruits#Off the Vine
+Mississippi Honeyberry#Missfruipb5iW3#0.95#595#fruits#TriCounty Produce
+Mississippi Honeyberry#MissfruiINiDbB#0.96#551#fruits#Simply Fresh
+Mississippi Honeyberry#MissfruiNUQ82a#0.93#396#fruits#Off the Vine
+Monkey Pot#MonkfruiXlTW4j#0.90#896#fruits#TriCounty Produce
+Monkey Pot#Monkfrui1p7a4h#0.88#344#fruits#Simply Fresh
+Monkey Pot#Monkfrui4eKggb#0.92#917#fruits#Off the Vine
+Monos Plum#Monofrui0Mv9aV#1.11#842#fruits#TriCounty Produce
+Monos Plum#Monofrui6iTGQY#1.14#570#fruits#Simply Fresh
+Monos Plum#MonofruiNu2uGH#1.13#978#fruits#Off the Vine
+Moosewood#MoosfruiMXEGex#0.86#969#fruits#TriCounty Produce
+Moosewood#Moosfrui8805mB#0.86#963#fruits#Simply Fresh
+Moosewood#MoosfruiOsnDFL#0.88#594#fruits#Off the Vine
+Natal Orange#NatafruitB8Kh2#0.42#332#fruits#TriCounty Produce
+Natal Orange#NatafruiOhqRrd#0.42#982#fruits#Simply Fresh
+Natal Orange#NatafruiRObMf6#0.41#268#fruits#Off the Vine
+Nectarine#NectfruilNfeD8#0.36#601#fruits#TriCounty Produce
+Nectarine#NectfruiQfjt6b#0.35#818#fruits#Simply Fresh
+Nectarine#Nectfrui5U7U96#0.37#930#fruits#Off the Vine
+Neem Tree#NeemfruiCruEMF#0.24#222#fruits#TriCounty Produce
+Neem Tree#NeemfruiGv0pv5#0.24#645#fruits#Simply Fresh
+Neem Tree#NeemfruiUFPVfk#0.25#601#fruits#Off the Vine
+New Zealand Spinach#New fruihDIgec#0.87#428#fruits#TriCounty Produce
+New Zealand Spinach#New fruiaoR9TP#0.87#630#fruits#Simply Fresh
+New Zealand Spinach#New fruiy8LBul#0.94#570#fruits#Off the Vine
+Olosapo#OlosfruiGXvaMm#0.76#388#fruits#TriCounty Produce
+Olosapo#OlosfruiESlpB3#0.76#560#fruits#Simply Fresh
+Olosapo#OlosfruiFNEkER#0.76#962#fruits#Off the Vine
+Oregon Grape#OregfruiWxhzrf#1.14#892#fruits#TriCounty Produce
+Oregon Grape#OregfruiMgjHUn#1.20#959#fruits#Simply Fresh
+Oregon Grape#OregfruiC5UCxX#1.17#419#fruits#Off the Vine
+Otaheite Apple#OtahfruilT0iFj#0.21#579#fruits#TriCounty Produce
+Otaheite Apple#Otahfrui92PyMY#0.22#857#fruits#Simply Fresh
+Otaheite Apple#OtahfruiLGD1EH#0.20#807#fruits#Off the Vine
+Oyster Plant#OystfruimGxOsj#0.77#835#fruits#TriCounty Produce
+Oyster Plant#Oystfrui1kudBX#0.81#989#fruits#Simply Fresh
+Oyster Plant#OystfruiaX3uO2#0.80#505#fruits#Off the Vine
+Panama Berry#PanafruiZG0Vp4#1.19#288#fruits#TriCounty Produce
+Panama Berry#PanafruiobvXPE#1.21#541#fruits#Simply Fresh
+Panama Berry#PanafruipaW8F3#1.16#471#fruits#Off the Vine
+Peach Tomato#PeacfruiQpovYH#1.20#475#fruits#TriCounty Produce
+Peach Tomato#PeacfruixYXLTN#1.18#655#fruits#Simply Fresh
+Peach Tomato#PeacfruiILDYAp#1.23#876#fruits#Off the Vine
+Peanut#Peanfruiy8M7pt#0.69#275#fruits#TriCounty Produce
+Peanut#PeanfruiEimbED#0.65#307#fruits#Simply Fresh
+Peanut#Peanfruic452Vc#0.68#937#fruits#Off the Vine
+Peanut Butter Fruit#PeanfruixEDt9Y#0.27#628#fruits#TriCounty Produce
+Peanut Butter Fruit#PeanfruiST0T0R#0.27#910#fruits#Simply Fresh
+Peanut Butter Fruit#Peanfrui7jeRN2#0.27#938#fruits#Off the Vine
+Pear#PearfruiB5YmSJ#0.20#945#fruits#TriCounty Produce
+Pear#PearfruiA93XZx#0.21#333#fruits#Simply Fresh
+Pear#PearfruioNKiIf#0.21#715#fruits#Off the Vine
+Pecan#PecafruiiTIv1Z#0.26#471#fruits#TriCounty Produce
+Pecan#PecafruiMGkqla#0.26#889#fruits#Simply Fresh
+Pecan#Pecafrui1szYz2#0.25#929#fruits#Off the Vine
+Purple Passion Fruit#Purpfrui4mMGkD#1.04#914#fruits#TriCounty Produce
+Purple Passion Fruit#Purpfrui5XOW3K#1.06#423#fruits#Simply Fresh
+Purple Passion Fruit#PurpfruifDTAgW#1.05#549#fruits#Off the Vine
+Red Mulberry#Red fruiVLOXIW#1.24#270#fruits#TriCounty Produce
+Red Mulberry#Red fruiXNXt4a#1.21#836#fruits#Simply Fresh
+Red Mulberry#Red fruiUseWLG#1.21#795#fruits#Off the Vine
+Red Princess#Red fruigJLR4V#0.23#829#fruits#TriCounty Produce
+Red Princess#Red fruinVKps5#0.23#558#fruits#Simply Fresh
+Red Princess#Red frui0jl9mg#0.24#252#fruits#Off the Vine
+Striped Screw Pine#StrifruiUKzjoU#0.60#226#fruits#TriCounty Produce
+Striped Screw Pine#StrifruivWLDzH#0.64#685#fruits#Simply Fresh
+Striped Screw Pine#StrifruiiF7CGH#0.60#983#fruits#Off the Vine
+Tapioca#Tapifruib4LCqt#0.40#955#fruits#TriCounty Produce
+Tapioca#TapifruiwgQLj9#0.41#889#fruits#Simply Fresh
+Tapioca#TapifruiZ6Igg3#0.41#655#fruits#Off the Vine
+Tavola#Tavofrui0k9XOt#1.16#938#fruits#TriCounty Produce
+Tavola#Tavofrui8DuRxL#1.08#979#fruits#Simply Fresh
+Tavola#TavofruiNZEuJZ#1.16#215#fruits#Off the Vine
+Tea#TeafruiL0357s#1.11#516#fruits#TriCounty Produce
+Tea#TeafruiD5soTf#1.13#970#fruits#Simply Fresh
+Tea#TeafruiOWq4oO#1.19#357#fruits#Off the Vine
+Ugli Fruit#UglifruipKNCpf#0.24#501#fruits#TriCounty Produce
+Ugli Fruit#UglifruifbDrzc#0.24#642#fruits#Simply Fresh
+Ugli Fruit#Uglifruiwx8or4#0.24#280#fruits#Off the Vine
+Vegetable Brain#VegefruieXLBoc#0.73#355#fruits#TriCounty Produce
+Vegetable Brain#Vegefruik5FSdl#0.71#498#fruits#Simply Fresh
+Vegetable Brain#VegefruiKBfzN0#0.72#453#fruits#Off the Vine
+White Walnut#Whitfruit3oVHL#0.30#501#fruits#TriCounty Produce
+White Walnut#WhitfruiHygydw#0.30#913#fruits#Simply Fresh
+White Walnut#WhitfruieNtplo#0.30#401#fruits#Off the Vine
+Wood Apple#WoodfruijVPRqA#0.68#501#fruits#TriCounty Produce
+Wood Apple#Woodfrui4Zk69T#0.68#616#fruits#Simply Fresh
+Wood Apple#WoodfruiuSLHZK#0.70#474#fruits#Off the Vine
+Yellow Horn#Yellfrui5igjjf#1.18#729#fruits#TriCounty Produce
+Yellow Horn#Yellfrui0DiPqa#1.13#517#fruits#Simply Fresh
+Yellow Horn#Yellfrui0ljvqC#1.14#853#fruits#Off the Vine
+Yellow Sapote#YellfruilGmCfq#0.93#204#fruits#TriCounty Produce
+Yellow Sapote#Yellfrui4J2mke#0.88#269#fruits#Simply Fresh
+Yellow Sapote#Yellfrui6PuXaL#0.86#575#fruits#Off the Vine
+Ylang-ylang#Ylanfrui3rmByO#0.76#429#fruits#TriCounty Produce
+Ylang-ylang#YlanfruiA80Nkq#0.76#886#fruits#Simply Fresh
+Ylang-ylang#YlanfruinUEm5d#0.72#747#fruits#Off the Vine
+Zapote Blanco#ZapofruisZ5sMA#0.67#428#fruits#TriCounty Produce
+Zapote Blanco#ZapofruilKxl7N#0.65#924#fruits#Simply Fresh
+Zapote Blanco#ZapofruiAe6Eu1#0.68#255#fruits#Off the Vine
+Zulu Nut#Zulufrui469K4k#0.71#445#fruits#TriCounty Produce
+Zulu Nut#ZulufruiWbz6vU#0.71#653#fruits#Simply Fresh
+Zulu Nut#Zulufrui0LJnWK#0.71#858#fruits#Off the Vine
+Artichoke#ArtivegeIuqmS4#0.71#282#vegetables#The Pantry
+Artichoke#Artivegebljjnf#0.69#66#vegetables#TriCounty Produce
+Artichoke#ArtivegeTa2lcF#0.70#618#vegetables#Off the Vine
+Asparagus#AspavegezC0cDl#0.23#70#vegetables#The Pantry
+Asparagus#AspavegeM1q5Kt#0.24#546#vegetables#TriCounty Produce
+Asparagus#AspavegeXWbCb8#0.24#117#vegetables#Off the Vine
+Basil#Basivegev08fzf#0.31#213#vegetables#The Pantry
+Basil#BasivegeF3Uha7#0.29#651#vegetables#TriCounty Produce
+Basil#BasivegeqR8SHC#0.31#606#vegetables#Off the Vine
+Bean#BeanvegegCFUOp#0.27#794#vegetables#The Pantry
+Bean#BeanvegeqMSEVq#0.27#468#vegetables#TriCounty Produce
+Bean#Beanvege4IGUwX#0.27#463#vegetables#Off the Vine
+Beet#BeetvegedEv4Ic#0.35#120#vegetables#The Pantry
+Beet#Beetvegegi1bz1#0.35#540#vegetables#TriCounty Produce
+Beet#BeetvegemztZcN#0.36#386#vegetables#Off the Vine
+Blackeyed Pea#Blacvege3TPldr#0.86#133#vegetables#The Pantry
+Blackeyed Pea#Blacvege3Zqnep#0.88#67#vegetables#TriCounty Produce
+Blackeyed Pea#Blacvege3khffZ#0.90#790#vegetables#Off the Vine
+Cabbage#CabbvegeY0c4Fw#0.82#726#vegetables#The Pantry
+Cabbage#CabbvegeoaK7Co#0.85#439#vegetables#TriCounty Produce
+Cabbage#CabbvegeVvO646#0.82#490#vegetables#Off the Vine
+Carrot#CarrvegeEbI0sw#0.45#717#vegetables#The Pantry
+Carrot#CarrvegeEZndWL#0.49#284#vegetables#TriCounty Produce
+Carrot#CarrvegewUkHao#0.47#122#vegetables#Off the Vine
+Cauliflower#Caulvege1CPeNG#0.68#756#vegetables#The Pantry
+Cauliflower#CaulvegedrPqib#0.66#269#vegetables#TriCounty Produce
+Cauliflower#CaulvegeT6cka8#0.65#728#vegetables#Off the Vine
+Chayote#ChayvegePRReGE#0.14#233#vegetables#The Pantry
+Chayote#Chayvegep058f7#0.14#88#vegetables#TriCounty Produce
+Chayote#ChayvegeoxO40S#0.14#611#vegetables#Off the Vine
+Corn#CornvegeukXkv6#0.72#632#vegetables#The Pantry
+Corn#CornvegePnPREC#0.72#609#vegetables#TriCounty Produce
+Corn#CornvegeO0GwoQ#0.70#664#vegetables#Off the Vine
+Cucumber#CucuvegeEqQeA7#0.94#499#vegetables#The Pantry
+Cucumber#CucuvegewmKbJ1#0.94#738#vegetables#TriCounty Produce
+Cucumber#CucuvegeUW6JaA#0.94#565#vegetables#Off the Vine
+Cantaloupe#CantvegeIHs9vJ#0.66#411#vegetables#The Pantry
+Cantaloupe#CantvegeEaDdST#0.66#638#vegetables#TriCounty Produce
+Cantaloupe#CantvegewWQEa0#0.64#682#vegetables#Off the Vine
+Carraway#CarrvegewuL4Ma#0.32#740#vegetables#The Pantry
+Carraway#CarrvegeyiWfBj#0.32#265#vegetables#TriCounty Produce
+Carraway#CarrvegeMjb1i9#0.31#732#vegetables#Off the Vine
+Celeriac#CelevegeoTBicd#0.74#350#vegetables#The Pantry
+Celeriac#CelevegeCNABoZ#0.70#261#vegetables#TriCounty Produce
+Celeriac#Celevege9LUeww#0.70#298#vegetables#Off the Vine
+Celery#Celevegej40ZCc#0.59#740#vegetables#The Pantry
+Celery#CelevegerYlVRy#0.58#734#vegetables#TriCounty Produce
+Celery#Celevege67eimC#0.58#619#vegetables#Off the Vine
+Chervil#ChervegeuH4Dge#0.09#502#vegetables#The Pantry
+Chervil#Chervegea1OyKO#0.09#299#vegetables#TriCounty Produce
+Chervil#Chervegeq56gMO#0.09#474#vegetables#Off the Vine
+Chicory#Chicvege79qoQ8#0.09#709#vegetables#The Pantry
+Chicory#ChicvegeTSVBQq#0.10#477#vegetables#TriCounty Produce
+Chicory#Chicvege6qpcyi#0.10#282#vegetables#Off the Vine
+Chinese Cabbage#ChinvegeFNsSRn#0.78#408#vegetables#The Pantry
+Chinese Cabbage#Chinvege2ldNr3#0.80#799#vegetables#TriCounty Produce
+Chinese Cabbage#ChinvegeK3R2Td#0.80#180#vegetables#Off the Vine
+Chinese Beans#ChinvegebxbyPy#0.45#654#vegetables#The Pantry
+Chinese Beans#ChinvegewKGwgx#0.45#206#vegetables#TriCounty Produce
+Chinese Beans#ChinvegevVjzC0#0.47#643#vegetables#Off the Vine
+Chines Kale#ChinvegeCfdkss#0.70#239#vegetables#The Pantry
+Chines Kale#Chinvege6V6Dne#0.65#548#vegetables#TriCounty Produce
+Chines Kale#ChinvegeB7vE3x#0.66#380#vegetables#Off the Vine
+Chinese Radish#ChinvegeXcM4eq#0.22#190#vegetables#The Pantry
+Chinese Radish#ChinvegeTdUBqN#0.22#257#vegetables#TriCounty Produce
+Chinese Radish#ChinvegeMXMms8#0.22#402#vegetables#Off the Vine
+Chinese Mustard#ChinvegeRDdpdl#0.33#149#vegetables#The Pantry
+Chinese Mustard#ChinvegeABDhNd#0.32#320#vegetables#TriCounty Produce
+Chinese Mustard#Chinvege8NPwa2#0.34#389#vegetables#Off the Vine
+Cilantro#CilavegeQXBEsW#0.60#674#vegetables#The Pantry
+Cilantro#CilavegeRgjkUG#0.60#355#vegetables#TriCounty Produce
+Cilantro#CilavegelT2msu#0.59#464#vegetables#Off the Vine
+Collard#CollvegesTGGNw#0.32#745#vegetables#The Pantry
+Collard#CollvegeAwdor5#0.32#124#vegetables#TriCounty Produce
+Collard#CollvegeQe900L#0.30#796#vegetables#Off the Vine
+Coriander#CorivegeXxp4xY#0.26#560#vegetables#The Pantry
+Coriander#Corivege9xBAT0#0.27#321#vegetables#TriCounty Produce
+Coriander#CorivegeCfNjBx#0.27#709#vegetables#Off the Vine
+Dandelion#DandvegeJNcnbr#0.11#285#vegetables#The Pantry
+Dandelion#DandvegeGwBkHZ#0.11#733#vegetables#TriCounty Produce
+Dandelion#DandvegeZfwVqn#0.11#57#vegetables#Off the Vine
+Daikon Radish#DaikvegeHHsd7M#0.61#743#vegetables#The Pantry
+Daikon Radish#DaikvegeIu17yC#0.62#459#vegetables#TriCounty Produce
+Daikon Radish#DaikvegePzFjqf#0.63#296#vegetables#Off the Vine
+Eggplant#EggpvegeKJtydN#0.55#200#vegetables#The Pantry
+Eggplant#EggpvegeQMKrNs#0.53#208#vegetables#TriCounty Produce
+Eggplant#EggpvegeN0WnSo#0.51#761#vegetables#Off the Vine
+English Pea#Englvegea1ytIn#0.40#457#vegetables#The Pantry
+English Pea#EnglvegerU9Vty#0.37#263#vegetables#TriCounty Produce
+English Pea#EnglvegeCmkd3y#0.39#430#vegetables#Off the Vine
+Fennel#Fennvegebz2UM7#0.76#545#vegetables#The Pantry
+Fennel#FennvegeQzjtZ3#0.78#795#vegetables#TriCounty Produce
+Fennel#FennvegeXSrW61#0.75#79#vegetables#Off the Vine
+Garlic#GarlvegesR2yel#0.76#478#vegetables#The Pantry
+Garlic#GarlvegeEQvt8W#0.77#349#vegetables#TriCounty Produce
+Garlic#GarlvegedljBdK#0.80#708#vegetables#Off the Vine
+Ginger#GingvegeMNiTc2#0.88#563#vegetables#The Pantry
+Ginger#Gingvegeq366Sn#0.89#738#vegetables#TriCounty Produce
+Ginger#GingvegeznyyVj#0.89#598#vegetables#Off the Vine
+Horseradish#HorsvegemSwISt#0.12#622#vegetables#The Pantry
+Horseradish#HorsvegetCOS0x#0.11#279#vegetables#TriCounty Produce
+Horseradish#Horsvegew6XXaS#0.12#478#vegetables#Off the Vine
+Japanese Eggplant#JapavegeTdKDCL#0.57#539#vegetables#The Pantry
+Japanese Eggplant#JapavegevsJfGa#0.58#782#vegetables#TriCounty Produce
+Japanese Eggplant#JapavegeCIrIxd#0.57#777#vegetables#Off the Vine
+Jerusalem Artichoke#Jeruvege928cr0#0.13#231#vegetables#The Pantry
+Jerusalem Artichoke#JeruvegeC2v086#0.14#123#vegetables#TriCounty Produce
+Jerusalem Artichoke#JeruvegeehCYzi#0.14#196#vegetables#Off the Vine
+Jicama#JicavegeRWYj9n#0.75#79#vegetables#The Pantry
+Jicama#JicavegeGk5LKH#0.71#292#vegetables#TriCounty Produce
+Jicama#JicavegeUjpaX1#0.70#308#vegetables#Off the Vine
+Kale#Kalevegext6RNT#0.55#765#vegetables#The Pantry
+Kale#KalevegeFsp17B#0.53#107#vegetables#TriCounty Produce
+Kale#KalevegeAffBTS#0.57#573#vegetables#Off the Vine
+Kiwifruit#KiwivegeloZBKJ#0.60#769#vegetables#The Pantry
+Kiwifruit#KiwivegenCQAHw#0.59#307#vegetables#TriCounty Produce
+Kiwifruit#Kiwivege0Gi3P2#0.59#235#vegetables#Off the Vine
+Kohlrabi#KohlvegeJFKZDl#0.26#406#vegetables#The Pantry
+Kohlrabi#Kohlvege32UTAj#0.28#613#vegetables#TriCounty Produce
+Kohlrabi#KohlvegejNQC1M#0.28#326#vegetables#Off the Vine
+Leek#Leekvege5iaFtg#0.70#580#vegetables#The Pantry
+Leek#Leekvegei9Wxbz#0.68#188#vegetables#TriCounty Produce
+Leek#LeekvegewY4mAc#0.70#473#vegetables#Off the Vine
+Lettuce#LettvegesK9wDR#0.55#716#vegetables#The Pantry
+Lettuce#LettvegeWzMyCM#0.57#83#vegetables#TriCounty Produce
+Lettuce#LettvegeHgfGG8#0.56#268#vegetables#Off the Vine
+Melons#Melovege6t93WF#0.11#252#vegetables#The Pantry
+Melons#Melovegeq9kz7T#0.12#558#vegetables#TriCounty Produce
+Melons#Melovege9kLTXN#0.12#382#vegetables#Off the Vine
+Mushroom#MushvegeSq53h8#0.59#365#vegetables#The Pantry
+Mushroom#Mushvegedq6lYP#0.59#444#vegetables#TriCounty Produce
+Mushroom#Mushvege8o27D2#0.55#467#vegetables#Off the Vine
+Okra#OkravegeTszQSL#0.55#62#vegetables#The Pantry
+Okra#OkravegeJBWmfh#0.58#165#vegetables#TriCounty Produce
+Okra#OkravegeD6tF9n#0.55#77#vegetables#Off the Vine
+Onion#OniovegejwimQo#0.80#186#vegetables#The Pantry
+Onion#OniovegeUOwwks#0.80#417#vegetables#TriCounty Produce
+Onion#OniovegezcRDrc#0.80#435#vegetables#Off the Vine
+Oregano#OregvegetlU7Ez#0.71#119#vegetables#The Pantry
+Oregano#Oregvege9h9ZKy#0.70#173#vegetables#TriCounty Produce
+Oregano#OregvegebXr0PJ#0.70#773#vegetables#Off the Vine
+Parsley#ParsvegeXFEjjN#0.83#502#vegetables#The Pantry
+Parsley#ParsvegejAg5C4#0.80#454#vegetables#TriCounty Produce
+Parsley#ParsvegehAtH2H#0.84#523#vegetables#Off the Vine
+Parsnip#Parsvegee9Lp6D#0.46#626#vegetables#The Pantry
+Parsnip#ParsvegeSxXHSA#0.47#411#vegetables#TriCounty Produce
+Parsnip#Parsvegea0stPf#0.44#403#vegetables#Off the Vine
+Pea#Peavegecq4SxR#0.18#342#vegetables#The Pantry
+Pea#Peavege46Gdp9#0.18#255#vegetables#TriCounty Produce
+Pea#Peavegeov1gc5#0.18#251#vegetables#Off the Vine
+Pepper#PeppvegeUcBYRp#0.33#52#vegetables#The Pantry
+Pepper#PeppvegeB60btP#0.35#107#vegetables#TriCounty Produce
+Pepper#PeppvegeG4tP3e#0.34#481#vegetables#Off the Vine
+Pigeon Pea#Pigevegec5bAtm#0.94#391#vegetables#The Pantry
+Pigeon Pea#Pigevegeb93eLi#0.91#447#vegetables#TriCounty Produce
+Pigeon Pea#PigevegejEBDRa#0.89#259#vegetables#Off the Vine
+Irish Potato#IrisvegeJNQqby#0.72#355#vegetables#The Pantry
+Irish Potato#Irisvegewq1PLd#0.72#601#vegetables#TriCounty Produce
+Irish Potato#IrisvegeAfFLdO#0.68#740#vegetables#Off the Vine
+Pumpkin#PumpvegeiYsPR8#0.25#776#vegetables#The Pantry
+Pumpkin#PumpvegelqP1Kh#0.25#189#vegetables#TriCounty Produce
+Pumpkin#Pumpvegeb3nQU5#0.26#207#vegetables#Off the Vine
+Radish#RadivegeNwwSBJ#0.16#613#vegetables#The Pantry
+Radish#Radivege0tIBnL#0.16#779#vegetables#TriCounty Produce
+Radish#RadivegeNLqJCf#0.16#731#vegetables#Off the Vine
+Rhubarb#RhubvegeREfOti#0.12#301#vegetables#The Pantry
+Rhubarb#Rhubvege4Jc3b7#0.12#557#vegetables#TriCounty Produce
+Rhubarb#RhubvegeaXqF7H#0.12#378#vegetables#Off the Vine
+Rosemary#Rosevege16QStc#0.73#380#vegetables#The Pantry
+Rosemary#RosevegeNf6Oem#0.75#622#vegetables#TriCounty Produce
+Rosemary#RosevegeFgsOyN#0.74#631#vegetables#Off the Vine
+Rutabaga#RutavegecUYfQ3#0.55#676#vegetables#The Pantry
+Rutabaga#RutavegejOG5DF#0.55#273#vegetables#TriCounty Produce
+Rutabaga#RutavegewEVjzV#0.53#452#vegetables#Off the Vine
+Salsify#SalsvegeViS9HF#0.11#537#vegetables#The Pantry
+Salsify#Salsvegemd3HAL#0.11#753#vegetables#TriCounty Produce
+Salsify#SalsvegeuRCnmq#0.10#787#vegetables#Off the Vine
+Savory#Savovegee4DRWl#0.21#456#vegetables#The Pantry
+Savory#SavovegerZ90Xm#0.21#642#vegetables#TriCounty Produce
+Savory#Savovegeje7yy7#0.22#328#vegetables#Off the Vine
+Sesame#Sesavege4NAWZE#0.84#54#vegetables#The Pantry
+Sesame#SesavegeMTc9IN#0.84#458#vegetables#TriCounty Produce
+Sesame#SesavegegOwAjo#0.83#125#vegetables#Off the Vine
+Shallots#ShalvegeUO2pDO#0.26#599#vegetables#The Pantry
+Shallots#ShalvegeY1sekb#0.27#647#vegetables#TriCounty Produce
+Shallots#ShalvegeSDC8VY#0.27#369#vegetables#Off the Vine
+Sugar Snap Peas#SugavegepUZDTl#0.47#308#vegetables#The Pantry
+Sugar Snap Peas#Sugavege1XyzNH#0.48#205#vegetables#TriCounty Produce
+Sugar Snap Peas#SugavegeJuaG7f#0.46#348#vegetables#Off the Vine
+Soybean#SoybvegeqxSVRL#0.70#639#vegetables#The Pantry
+Soybean#SoybvegezEMjOG#0.68#423#vegetables#TriCounty Produce
+Soybean#SoybvegebanSFq#0.67#268#vegetables#Off the Vine
+Spaghetti Squash#SpagvegeMNO1yC#0.12#753#vegetables#The Pantry
+Spaghetti Squash#SpagvegeilpUaD#0.13#604#vegetables#TriCounty Produce
+Spaghetti Squash#SpagvegeAOoZNX#0.13#431#vegetables#Off the Vine
+Spinach#SpinvegeegXXou#0.10#742#vegetables#The Pantry
+Spinach#SpinvegeVcqXL6#0.11#708#vegetables#TriCounty Produce
+Spinach#SpinvegetZ26DN#0.11#625#vegetables#Off the Vine
+Sweet Potato#SweevegepNDQWb#0.94#720#vegetables#The Pantry
+Sweet Potato#Sweevegepnw7Tm#0.90#377#vegetables#TriCounty Produce
+Sweet Potato#Sweevegeyk0C82#0.89#242#vegetables#Off the Vine
+Swiss Chard#SwisvegeksalTA#0.54#545#vegetables#The Pantry
+Swiss Chard#SwisvegeKm2Kze#0.54#472#vegetables#TriCounty Produce
+Swiss Chard#SwisvegehteuMk#0.56#142#vegetables#Off the Vine
+Taro#Tarovege3fpGV6#0.87#155#vegetables#The Pantry
+Taro#TarovegerZkmof#0.86#371#vegetables#TriCounty Produce
+Taro#TarovegeXKPuzc#0.89#443#vegetables#Off the Vine
+Tarragon#TarrvegeCzVC6U#0.18#491#vegetables#The Pantry
+Tarragon#TarrvegesIkEfS#0.17#65#vegetables#TriCounty Produce
+Tarragon#TarrvegerZsKFP#0.18#180#vegetables#Off the Vine
+Thyme#Thymvege8Rv72c#0.41#442#vegetables#The Pantry
+Thyme#ThymvegeJoUdQS#0.42#237#vegetables#TriCounty Produce
+Thyme#ThymvegeRck5uO#0.43#491#vegetables#Off the Vine
+Tomato#Tomavegey0NHGK#0.31#60#vegetables#The Pantry
+Tomato#TomavegeKAjRUn#0.30#630#vegetables#TriCounty Produce
+Tomato#TomavegePZOHlH#0.30#70#vegetables#Off the Vine
+Turnip#TurnvegeRVQiV5#0.44#580#vegetables#The Pantry
+Turnip#TurnvegeVjIX9D#0.45#743#vegetables#TriCounty Produce
+Turnip#TurnvegelFhvuJ#0.44#219#vegetables#Off the Vine
+Watercress#WatevegelwzPLQ#0.54#230#vegetables#The Pantry
+Watercress#Watevege8oeDCT#0.54#774#vegetables#TriCounty Produce
+Watercress#Watevegexr8L1t#0.55#185#vegetables#Off the Vine
+Watermelon#WatevegeL83MRH#0.19#698#vegetables#The Pantry
+Watermelon#WatevegeR2S4Dq#0.21#488#vegetables#TriCounty Produce
+Watermelon#WatevegepFPXQu#0.21#439#vegetables#Off the Vine
+Kamote#KamovegegdON75#0.13#218#vegetables#The Pantry
+Kamote#KamovegevupDBf#0.13#98#vegetables#TriCounty Produce
+Kamote#KamovegeSQX7IA#0.14#703#vegetables#Off the Vine
+Alogbati#AlogvegeB1WaJU#0.41#775#vegetables#The Pantry
+Alogbati#AlogvegeVr5cPP#0.40#789#vegetables#TriCounty Produce
+Alogbati#AlogvegeyTUQzy#0.40#416#vegetables#Off the Vine
+Ampalaya#AmpavegemR9fSd#0.85#107#vegetables#The Pantry
+Ampalaya#AmpavegeJDu9Im#0.90#676#vegetables#TriCounty Produce
+Ampalaya#AmpavegepL8GH5#0.86#728#vegetables#Off the Vine
+Dahon ng sili#Dahovege6X9grk#0.11#369#vegetables#The Pantry
+Dahon ng sili#DahovegeiHZjQT#0.11#141#vegetables#TriCounty Produce
+Dahon ng sili#DahovegeoCDAH8#0.12#517#vegetables#Off the Vine
+Gabi#GabivegeVm4Xk3#0.44#396#vegetables#The Pantry
+Gabi#Gabivegeu6woqK#0.42#722#vegetables#TriCounty Produce
+Gabi#GabivegezcA7q1#0.42#394#vegetables#Off the Vine
+Kabute#Kabuvege6Tqrif#0.16#123#vegetables#The Pantry
+Kabute#KabuvegeA3uYdG#0.15#183#vegetables#TriCounty Produce
+Kabute#KabuvegeXW6ZiI#0.16#624#vegetables#Off the Vine
+Kamoteng Kahoy#KamovegeAdW37X#0.42#782#vegetables#The Pantry
+Kamoteng Kahoy#KamovegetFlqpC#0.42#515#vegetables#TriCounty Produce
+Kamoteng Kahoy#KamovegeMvxoLn#0.40#166#vegetables#Off the Vine
+Kangkong#KangvegeSFTvEz#0.35#759#vegetables#The Pantry
+Kangkong#KangvegeRLR6gL#0.34#695#vegetables#TriCounty Produce
+Kangkong#Kangvege9BFo14#0.35#783#vegetables#Off the Vine
+Labanos#Labavege3qrWJL#0.94#514#vegetables#The Pantry
+Labanos#LabavegekgVWDH#0.89#210#vegetables#TriCounty Produce
+Labanos#LabavegeiVPgMx#0.89#207#vegetables#Off the Vine
+Labong#LabovegeX3O8yz#0.85#722#vegetables#The Pantry
+Labong#LabovegeI1wSEs#0.87#472#vegetables#TriCounty Produce
+Labong#LabovegeOPiQht#0.85#740#vegetables#Off the Vine
+Malunggay#MaluvegeHkwAFm#0.30#252#vegetables#The Pantry
+Malunggay#Maluvegez6TiSY#0.30#245#vegetables#TriCounty Produce
+Malunggay#MaluvegewzY37D#0.31#405#vegetables#Off the Vine
+Munggo#MungvegeqeuwGw#0.25#362#vegetables#The Pantry
+Munggo#MungvegeNhqWvL#0.26#360#vegetables#TriCounty Produce
+Munggo#MungvegeGxNxQC#0.25#555#vegetables#Off the Vine
+Pechay#PechvegezDeHFZ#0.36#401#vegetables#The Pantry
+Pechay#Pechvegehi4Fcx#0.35#723#vegetables#TriCounty Produce
+Pechay#Pechvege8Pq8Eo#0.36#141#vegetables#Off the Vine
+Sigarilyas#SigavegeMJrtlV#0.88#335#vegetables#The Pantry
+Sigarilyas#SigavegeLhsoOB#0.87#768#vegetables#TriCounty Produce
+Sigarilyas#SigavegeS6RJcA#0.93#356#vegetables#Off the Vine
+Sitaw#Sitavege0hMi9z#0.65#153#vegetables#The Pantry
+Sitaw#Sitavegeez1g6N#0.67#561#vegetables#TriCounty Produce
+Sitaw#Sitavege0BCNeF#0.66#674#vegetables#Off the Vine
+Talong#TalovegevZjVK6#0.10#530#vegetables#The Pantry
+Talong#TalovegexX4MRw#0.09#305#vegetables#TriCounty Produce
+Talong#TalovegeO3U2ze#0.10#126#vegetables#Off the Vine
+Toge#TogevegeYelJUw#0.54#449#vegetables#The Pantry
+Toge#Togevegeilr1xK#0.54#274#vegetables#TriCounty Produce
+Toge#Togevegesvjnyn#0.51#316#vegetables#Off the Vine
+Ube#UbevegeoPnxvb#0.56#397#vegetables#The Pantry
+Ube#Ubevege2CNyve#0.55#450#vegetables#TriCounty Produce
+Ube#UbevegeC43sVj#0.55#263#vegetables#Off the Vine
+Upo#UpovegecOGRqC#0.22#404#vegetables#The Pantry
+Upo#Upovegekjl2wl#0.22#541#vegetables#TriCounty Produce
+Upo#UpovegemTTTwI#0.23#459#vegetables#Off the Vine
+Edamame#EdamvegeVYtk8z#0.79#296#vegetables#The Pantry
+Edamame#Edamvege608vXi#0.78#700#vegetables#TriCounty Produce
+Edamame#Edamvege1jiqGY#0.75#115#vegetables#Off the Vine
+Hairy melon#HairvegeFYFHIw#0.71#789#vegetables#The Pantry
+Hairy melon#HairvegeS7AAqI#0.72#302#vegetables#TriCounty Produce
+Hairy melon#HairvegeO6WJHL#0.72#444#vegetables#Off the Vine
+Burdock#BurdvegeyLstLV#0.56#761#vegetables#The Pantry
+Burdock#BurdvegeZsqAjT#0.56#582#vegetables#TriCounty Produce
+Burdock#BurdvegeycF7mo#0.55#566#vegetables#Off the Vine
+Snake gourd#SnakvegesfHGvt#0.92#626#vegetables#The Pantry
+Snake gourd#SnakvegedlNiBk#0.92#669#vegetables#TriCounty Produce
+Snake gourd#Snakvegec5n1UM#0.92#143#vegetables#Off the Vine
+Wasabi#Wasavege5P5pZp#0.67#751#vegetables#The Pantry
+Wasabi#Wasavege6EEE9r#0.68#559#vegetables#TriCounty Produce
+Wasabi#Wasavege1ve7TY#0.65#61#vegetables#Off the Vine
+Yam#YamvegeRN9ONH#0.57#438#vegetables#The Pantry
+Yam#YamvegeWjdzeA#0.56#564#vegetables#TriCounty Produce
+Yam#YamvegeI1AnyI#0.56#456#vegetables#Off the Vine
+Apple Fritters#AppldessDj96hw#6.12#16#desserts#Mom's Kitchen
+Apple Fritters#AppldessrN1kvM#6.06#7#desserts#The Baking Pan
+Banana Split#Banadess7tpjkJ#10.86#10#desserts#Mom's Kitchen
+Banana Split#Banadessfif758#11.07#14#desserts#The Baking Pan
+Blueberry Boy Bait#BluedesseX2LVU#3.72#16#desserts#Mom's Kitchen
+Blueberry Boy Bait#Bluedess9zLhaH#3.93#9#desserts#The Baking Pan
+Candied Cranberries#CanddessjW92p3#1.77#9#desserts#Mom's Kitchen
+Candied Cranberries#CanddesskhtVoQ#1.72#0#desserts#The Baking Pan
+Daiquiri Souffle#DaiqdessebnYcy#9.54#15#desserts#Mom's Kitchen
+Daiquiri Souffle#DaiqdessfM1DnX#9.72#6#desserts#The Baking Pan
+Bananas Flambe#BanadesscczumD#6.94#12#desserts#Mom's Kitchen
+Bananas Flambe#Banadess8qNfxd#7.07#16#desserts#The Baking Pan
+Pie, Apple#Pie,desshcSHhT#7.88#11#desserts#Mom's Kitchen
+Pie, Apple#Pie,dessTbiwDp#7.88#15#desserts#The Baking Pan
+Pie, Pumpkin#Pie,desswhPBPB#6.00#20#desserts#Mom's Kitchen
+Pie, Pumpkin#Pie,dessDg3NWl#6.24#19#desserts#The Baking Pan
+Pie, Blueberry#Pie,dessw9VdgD#2.14#3#desserts#Mom's Kitchen
+Pie, Blueberry#Pie,dessiSjZKD#2.12#1#desserts#The Baking Pan
+Pie, Pecan#Pie,dess2NqhNR#12.70#20#desserts#Mom's Kitchen
+Pie, Pecan#Pie,dessB1LfcE#12.33#12#desserts#The Baking Pan
+Pie, Cranberry Apple#Pie,dess1mL7IS#10.16#7#desserts#Mom's Kitchen
+Pie, Cranberry Apple#Pie,dessmDhkUA#10.16#11#desserts#The Baking Pan
+Pie, Banana Cream#Pie,dessH80DuG#7.35#6#desserts#Mom's Kitchen
+Pie, Banana Cream#Pie,dessf1YvFb#7.08#11#desserts#The Baking Pan
+Pie, Key Lime#Pie,desshtli5N#4.85#2#desserts#Mom's Kitchen
+Pie, Key Lime#Pie,dessMwQkKm#5.13#1#desserts#The Baking Pan
+Pie, Lemon Meringue#Pie,dess9naVkX#3.74#7#desserts#Mom's Kitchen
+Pie, Lemon Meringue#Pie,dessKYcNML#3.67#5#desserts#The Baking Pan
+Pie, Caramel#Pie,dessSUuiIU#2.27#9#desserts#Mom's Kitchen
+Pie, Caramel#Pie,dessvo8uHh#2.33#4#desserts#The Baking Pan
+Pie, Raspberry#Pie,dessUHhMlS#2.36#0#desserts#Mom's Kitchen
+Pie, Raspberry#Pie,dessJflbf5#2.36#2#desserts#The Baking Pan
+Ice Cream, Chocolate#Ice desseXuyxx#1.44#9#desserts#Mom's Kitchen
+Ice Cream, Chocolate#Ice dessASBohf#1.41#13#desserts#The Baking Pan
+Ice Cream, Vanilla#Ice dessYnzbbt#11.92#19#desserts#Mom's Kitchen
+Ice Cream, Vanilla#Ice dessUBBKp8#11.58#10#desserts#The Baking Pan
+Ice Cream, Strawberry#Ice dessfTwKhD#1.90#14#desserts#Mom's Kitchen
+Ice Cream, Strawberry#Ice dessaO9Fxf#1.99#6#desserts#The Baking Pan
+Ice Cream, Rocky Road#Ice dessyIri3P#13.10#20#desserts#Mom's Kitchen
+Ice Cream, Rocky Road#Ice dessZuLr8F#13.48#13#desserts#The Baking Pan
+Ice Cream, Mint Chocolate Chip#Ice dessV1IGG7#5.75#4#desserts#Mom's Kitchen
+Ice Cream, Mint Chocolate Chip#Ice dessX1gEQ4#5.64#1#desserts#The Baking Pan
+Ice Cream Sundae#Ice dessbhlAXt#5.62#11#desserts#Mom's Kitchen
+Ice Cream Sundae#Ice dessByapxl#5.72#16#desserts#The Baking Pan
+Cobbler, Peach#CobbdessYUGeOB#10.14#20#desserts#Mom's Kitchen
+Cobbler, Peach#CobbdessXfEtUK#10.43#16#desserts#The Baking Pan
+Cobbler, Berry-Pecan#Cobbdessx3htak#5.36#12#desserts#Mom's Kitchen
+Cobbler, Berry-Pecan#Cobbdesse4FUVI#5.41#8#desserts#The Baking Pan
+Cobbler, Blueberry#CobbdessbiI0oF#3.78#11#desserts#Mom's Kitchen
+Cobbler, Blueberry#CobbdessMXxbBN#3.57#2#desserts#The Baking Pan
+Cobbler, Cherry#CobbdessNSa8QW#12.58#0#desserts#Mom's Kitchen
+Cobbler, Cherry#CobbdessA1dADa#12.10#10#desserts#The Baking Pan
+Cobbler, Huckleberry#Cobbdess3t6O8d#3.99#18#desserts#Mom's Kitchen
+Cobbler, Huckleberry#CobbdessGI9euK#3.88#0#desserts#The Baking Pan
+Cobbler, Rhubarb#Cobbdess22X40Z#9.54#0#desserts#Mom's Kitchen
+Cobbler, Rhubarb#CobbdessPfnCT0#9.27#18#desserts#The Baking Pan
+Cobbler, Strawberry#CobbdessI78188#12.43#0#desserts#Mom's Kitchen
+Cobbler, Strawberry#CobbdessH3LdgQ#12.20#3#desserts#The Baking Pan
+Cobbler, Zucchini#Cobbdess5rK4dP#11.24#3#desserts#Mom's Kitchen
+Cobbler, Zucchini#Cobbdess4Ez8kS#10.51#10#desserts#The Baking Pan
+Brownies#BrowdessmogdTl#7.62#9#desserts#Mom's Kitchen
+Brownies#Browdess84Qc1z#7.55#9#desserts#The Baking Pan
+Fudge Bar#Fudgdess8iXSyf#11.72#6#desserts#Mom's Kitchen
+Fudge Bar#FudgdessakU1Id#12.29#5#desserts#The Baking Pan
+Cookies, Oatmeal#Cookdessnq9Oya#2.84#15#desserts#Mom's Kitchen
+Cookies, Oatmeal#CookdessBhgp7p#2.68#10#desserts#The Baking Pan
+Cookies, Chocolate Chip#CookdessRVszsZ#12.73#17#desserts#Mom's Kitchen
+Cookies, Chocolate Chip#CookdessSOoHmT#12.26#19#desserts#The Baking Pan
+Cookies, Peanut Butter#Cookdess2UcMI2#7.82#5#desserts#Mom's Kitchen
+Cookies, Peanut Butter#Cookdess1cILme#7.46#20#desserts#The Baking Pan
+Mousse, Chocolate#MousdessDpN4sQ#6.25#20#desserts#Mom's Kitchen
+Mousse, Chocolate#Mousdess8FyFT8#5.96#1#desserts#The Baking Pan
+Mousse, Blueberry Maple#MousdessacwrkO#7.28#7#desserts#Mom's Kitchen
+Mousse, Blueberry Maple#MousdessbiCMFg#7.21#12#desserts#The Baking Pan
+Mousse, Chocolate Banana#MousdessIeW4qz#5.13#2#desserts#Mom's Kitchen
+Mousse, Chocolate Banana#Mousdess1De9oL#5.08#19#desserts#The Baking Pan
+Mousse, Cherry#Mousdesss1bF8H#13.05#20#desserts#Mom's Kitchen
+Mousse, Cherry#Mousdess0ujevx#12.43#1#desserts#The Baking Pan
+Mousse, Eggnog#MousdessZ38hXj#9.07#10#desserts#Mom's Kitchen
+Mousse, Eggnog#Mousdesshs05ST#8.81#8#desserts#The Baking Pan
+Mousse, Strawberry#MousdessHCDlBK#5.58#3#desserts#Mom's Kitchen
+Mousse, Strawberry#MousdessSZ4PyW#5.36#6#desserts#The Baking Pan
+Sherbet, Cantaloupe#Sherdess3DCxUg#3.11#9#desserts#Mom's Kitchen
+Sherbet, Cantaloupe#Sherdesscp2VIz#2.99#7#desserts#The Baking Pan
+Sherbet, Lemon Milk#Sherdess1JVFOS#7.57#9#desserts#Mom's Kitchen
+Sherbet, Lemon Milk#SherdessC865vu#7.57#0#desserts#The Baking Pan
+Sherbet, Orange Crush#Sherdess8W8Mb9#4.32#18#desserts#Mom's Kitchen
+Sherbet, Orange Crush#SherdessxmVJBF#4.16#10#desserts#The Baking Pan
+Sherbet, Blueberry#SherdessFAgxqp#3.46#9#desserts#Mom's Kitchen
+Sherbet, Blueberry#SherdessMPL87u#3.60#6#desserts#The Baking Pan
+Sherbet, Raspberry#Sherdesse86ugA#6.08#1#desserts#Mom's Kitchen
+Sherbet, Raspberry#Sherdesslc1etR#5.85#12#desserts#The Baking Pan
+Sherbet, Strawberry#SherdessFwv09m#4.63#17#desserts#Mom's Kitchen
+Sherbet, Strawberry#SherdessKB0H7q#4.81#20#desserts#The Baking Pan
+Tart, Apple#TartdessrsTyXA#3.35#18#desserts#Mom's Kitchen
+Tart, Apple#Tartdessp7pyiy#3.13#11#desserts#The Baking Pan
+Tart, Almond#TartdessC7FARL#6.62#10#desserts#Mom's Kitchen
+Tart, Almond#Tartdess1V1A1c#6.68#13#desserts#The Baking Pan
+Tart, Blueberry#TartdesssQZRXX#10.28#10#desserts#Mom's Kitchen
+Tart, Blueberry#TartdessUSJSuc#10.28#9#desserts#The Baking Pan
+Tart, Chocolate-Pear#Tartdess2pdOE4#5.67#17#desserts#Mom's Kitchen
+Tart, Chocolate-Pear#TartdessL3aEDd#5.51#9#desserts#The Baking Pan
+Tart, Lemon Fudge#Tartdess9DhZUT#3.88#3#desserts#Mom's Kitchen
+Tart, Lemon Fudge#TartdesshzLOWt#3.96#13#desserts#The Baking Pan
+Tart, Pecan#TartdessvSbXzd#11.80#3#desserts#Mom's Kitchen
+Tart, Pecan#Tartdess6YXJec#11.04#13#desserts#The Baking Pan
+Tart, Pineapple#TartdesseMfJFe#9.01#18#desserts#Mom's Kitchen
+Tart, Pineapple#TartdessA2Wftr#8.44#13#desserts#The Baking Pan
+Tart, Pear#Tartdess4a1BUc#10.09#2#desserts#Mom's Kitchen
+Tart, Pear#TartdessNw8YPG#10.68#5#desserts#The Baking Pan
+Tart, Raspberry#TartdessAVnpP6#6.18#7#desserts#Mom's Kitchen
+Tart, Raspberry#TartdessfVxZFf#5.95#9#desserts#The Baking Pan
+Tart, Strawberry#Tartdess4IUcZW#4.75#8#desserts#Mom's Kitchen
+Tart, Strawberry#Tartdess2BeEDb#4.61#17#desserts#The Baking Pan
+Tart, Raspberry#TartdesshyBd24#1.85#5#desserts#Mom's Kitchen
+Tart, Raspberry#Tartdess5fqxgy#1.94#20#desserts#The Baking Pan
+Trifle, Berry#TrifdessmEkbU2#12.48#19#desserts#Mom's Kitchen
+Trifle, Berry#TrifdessAV9Ix8#12.60#18#desserts#The Baking Pan
+Trifle, American#TrifdesscsdSCd#4.70#17#desserts#Mom's Kitchen
+Trifle, American#TrifdessTArskm#4.35#11#desserts#The Baking Pan
+Trifle, English#TrifdessX87q8T#8.20#9#desserts#Mom's Kitchen
+Trifle, English#Trifdess52l955#8.12#11#desserts#The Baking Pan
+Trifle, Orange#TrifdesslUwxwe#9.74#15#desserts#Mom's Kitchen
+Trifle, Orange#TrifdessFrfCHP#10.22#1#desserts#The Baking Pan
+Trifle, Pumpkin#TrifdessJKFN96#4.72#7#desserts#Mom's Kitchen
+Trifle, Pumpkin#TrifdessMNw4EV#4.95#16#desserts#The Baking Pan
+Trifle, Scottish#TrifdessFa0JdK#13.63#0#desserts#Mom's Kitchen
+Trifle, Scottish#TrifdessAAUQCN#14.03#6#desserts#The Baking Pan
+Trifle, Sherry#TrifdesscuttJg#4.42#5#desserts#Mom's Kitchen
+Trifle, Sherry#TrifdesspRGpfP#4.21#19#desserts#The Baking Pan
+Trifle, Strawberry#TrifdessAd5TpV#3.58#11#desserts#Mom's Kitchen
+Trifle, Strawberry#Trifdess1rtW0A#3.58#3#desserts#The Baking Pan
+Trifle, Scotch Whiskey#Trifdess2zJsGi#5.44#5#desserts#Mom's Kitchen
+Trifle, Scotch Whiskey#TrifdessL8nuI6#5.18#5#desserts#The Baking Pan
+Cheesecake, Amaretto#CheedessOJBqfD#11.89#5#desserts#Mom's Kitchen
+Cheesecake, Amaretto#CheedessVnDf14#11.89#9#desserts#The Baking Pan
+Cheesecake, Apple#Cheedessuks1YK#11.22#15#desserts#Mom's Kitchen
+Cheesecake, Apple#CheedessMYKaKK#11.01#14#desserts#The Baking Pan
+Cheesecake, Apricot#CheedessKUxTYY#12.34#16#desserts#Mom's Kitchen
+Cheesecake, Apricot#CheedessMvB1pr#11.88#18#desserts#The Baking Pan
+Cheesecake, Australian#CheedessQ9WAIn#2.70#9#desserts#Mom's Kitchen
+Cheesecake, Australian#CheedessE6Jyjc#2.53#14#desserts#The Baking Pan
+Cheesecake, Arkansas#CheedessTbqzmw#6.98#9#desserts#Mom's Kitchen
+Cheesecake, Arkansas#CheedesstWJZfC#6.66#5#desserts#The Baking Pan
+Cheesecake, Blueberry#Cheedessyo51KL#8.07#11#desserts#Mom's Kitchen
+Cheesecake, Blueberry#Cheedess4Hz7P4#8.62#5#desserts#The Baking Pan
+Cheesecake, Cherry#CheedessEahRkC#4.40#14#desserts#Mom's Kitchen
+Cheesecake, Cherry#Cheedess3Nx4jZ#4.65#3#desserts#The Baking Pan
+Cheesecake, Cran-Raspberry#CheedessrJsr9i#13.47#20#desserts#Mom's Kitchen
+Cheesecake, Cran-Raspberry#CheedesshcuXCy#14.00#6#desserts#The Baking Pan
+Cheesecake, German Chocolate#CheedesswayvJL#12.03#16#desserts#Mom's Kitchen
+Cheesecake, German Chocolate#CheedessebTAeB#11.58#0#desserts#The Baking Pan
+Cheesecake, Turtle#CheedessLqgeIA#12.19#6#desserts#Mom's Kitchen
+Cheesecake, Turtle#CheedessvyNohA#12.07#19#desserts#The Baking Pan
+Brownies, Apple#BrowdessIDW1Cc#5.44#12#desserts#Mom's Kitchen
+Brownies, Apple#BrowdessyRMrAH#5.14#12#desserts#The Baking Pan
+Brownies, Fudge#BrowdessmIHIFJ#5.19#8#desserts#Mom's Kitchen
+Brownies, Fudge#BrowdessqewJ38#5.10#17#desserts#The Baking Pan
+Brownies, Almond Macaroon#BrowdessniK7QI#10.57#3#desserts#Mom's Kitchen
+Brownies, Almond Macaroon#BrowdessgkXURH#10.36#17#desserts#The Baking Pan
+Brownies, Butterscotch#BrowdesslpA06E#7.16#13#desserts#Mom's Kitchen
+Brownies, Butterscotch#BrowdessK5hofE#7.30#6#desserts#The Baking Pan
+Brownies, Caramel#BrowdessVGfoA8#3.07#3#desserts#Mom's Kitchen
+Brownies, Caramel#Browdess5jvVMM#3.13#11#desserts#The Baking Pan
+Brownies, Cherry#Browdessyoa66A#3.39#17#desserts#Mom's Kitchen
+Brownies, Cherry#BrowdessIg2JuF#3.39#11#desserts#The Baking Pan
+Brownies, Chocolate Chip#Browdessb9dc59#6.18#10#desserts#Mom's Kitchen
+Brownies, Chocolate Chip#BrowdessvW4nOx#6.43#14#desserts#The Baking Pan
+Brownies, Coconut#BrowdessWPHrVR#3.06#15#desserts#Mom's Kitchen
+Brownies, Coconut#BrowdessGVBlML#2.86#11#desserts#The Baking Pan
+Brownies, Cream Cheese#Browdess1OyRay#12.74#4#desserts#Mom's Kitchen
+Brownies, Cream Cheese#Browdess2fRsNv#12.61#19#desserts#The Baking Pan
+Brownies, Fudge Mint#Browdessl7DP7k#11.45#14#desserts#Mom's Kitchen
+Brownies, Fudge Mint#Browdessv70VKQ#11.34#16#desserts#The Baking Pan
+Brownies, Mint Chip#BrowdessDDMvF7#1.81#15#desserts#Mom's Kitchen
+Brownies, Mint Chip#Browdess0j9PBD#1.84#9#desserts#The Baking Pan
+Cake, Angel Food#CakedessEaqGaE#11.18#3#desserts#Mom's Kitchen
+Cake, Angel Food#CakedessJyAyFe#11.18#14#desserts#The Baking Pan
+Cake, Chocolate#CakedessKLXFbn#10.11#7#desserts#Mom's Kitchen
+Cake, Chocolate#CakedessfNP5Hg#9.91#14#desserts#The Baking Pan
+Cake, Carrot#CakedessUTgMoV#4.20#13#desserts#Mom's Kitchen
+Cake, Carrot#CakedessQdkaYg#4.00#3#desserts#The Baking Pan
+Cake, Lemon Blueberry#CakedessepkeEW#11.73#16#desserts#Mom's Kitchen
+Cake, Lemon Blueberry#CakedessHTKyQs#12.42#16#desserts#The Baking Pan
+Cake Triple Fudge#CakedessiZ75lR#7.92#7#desserts#Mom's Kitchen
+Cake Triple Fudge#CakedessWRrSXP#8.00#15#desserts#The Baking Pan
+Cake, Walnut#CakedessveYVXZ#10.83#17#desserts#Mom's Kitchen
+Cake, Walnut#Cakedesse22rT5#11.04#7#desserts#The Baking Pan
+Cake, French Apple#CakedessjA2Kxv#1.95#0#desserts#Mom's Kitchen
+Cake, French Apple#CakedessNBHCk0#1.86#20#desserts#The Baking Pan
+Cake, Fig#CakedessOncX4y#6.82#3#desserts#Mom's Kitchen
+Cake, Fig#CakedessTJtffn#7.08#10#desserts#The Baking Pan
+Cake, Maple#CakedessnoGPRF#3.04#11#desserts#Mom's Kitchen
+Cake, Maple#CakedessfVattM#3.22#4#desserts#The Baking Pan
+Cake, Devil's Food#CakedessiXcDCt#4.73#7#desserts#Mom's Kitchen
+Cake, Devil's Food#CakedessnBZk45#4.82#6#desserts#The Baking Pan
+Cake, Double-Lemon#CakedesskeS0Vd#3.46#9#desserts#Mom's Kitchen
+Cake, Double-Lemon#Cakedess50vx53#3.60#6#desserts#The Baking Pan
+Sorbet, Blackberry#SorbdessQoa0CE#9.88#15#desserts#Mom's Kitchen
+Sorbet, Blackberry#SorbdessqoOYzv#9.78#9#desserts#The Baking Pan
diff --git a/examples_java/src/db/GettingStarted/vendors.txt b/examples_java/src/db/GettingStarted/vendors.txt
new file mode 100644
index 0000000..528e1b1
--- /dev/null
+++ b/examples_java/src/db/GettingStarted/vendors.txt
@@ -0,0 +1,6 @@
+TriCounty Produce#309 S. Main Street#Middle Town#MN#55432#763 555 5761#Mort Dufresne#763 555 5765
+Simply Fresh#15612 Bogart Lane#Harrigan#WI#53704#420 333 3912#Cheryl Swedberg#420 333 3952
+Off the Vine#133 American Ct.#Centennial#IA#52002#563 121 3800#Bob King#563 121 3800 x54
+The Pantry#1206 N. Creek Way#Middle Town#MN#55432#763 555 3391#Sully Beckstrom#763 555 3391
+Mom's Kitchen#53 Yerman Ct.#Middle Town#MN#55432#763 554 9200#Maggie Kultgen#763 554 9200 x12
+The Baking Pan#1415 53rd Ave.#Dutchin#MN#56304#320 442 2277#Mike Roan#320 442 6879
diff --git a/examples_java/src/db/LockExample.java b/examples_java/src/db/LockExample.java
new file mode 100644
index 0000000..7b20838
--- /dev/null
+++ b/examples_java/src/db/LockExample.java
@@ -0,0 +1,226 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 1997-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package db;
+
+import com.sleepycat.db.*;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.InputStreamReader;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.util.Vector;
+
+//
+// An example of a program using Lock and related classes.
+//
+class LockExample {
+ private static final String progname = "LockExample";
+ private static final File LOCK_HOME = new File("TESTDIR");
+ Environment dbenv;
+
+ public LockExample(File home, int maxlocks, boolean do_unlink)
+ throws DatabaseException, FileNotFoundException {
+
+ if (do_unlink) {
+ Environment.remove(home, true, null);
+ }
+
+ EnvironmentConfig config = new EnvironmentConfig();
+ config.setErrorStream(System.err);
+ config.setErrorPrefix("LockExample");
+ config.setMaxLocks(maxlocks);
+ config.setAllowCreate(true);
+ config.setInitializeLocking(true);
+ dbenv = new Environment(home, config);
+ }
+
+ public void close() throws DatabaseException {
+ dbenv.close();
+ }
+
+ // Prompts for a line, returning the default answer if a blank
+ // line is entered.
+ //
+ public static String askForLine(InputStreamReader reader,
+ PrintStream out, String prompt,
+ String defaultAnswer) {
+ String result;
+ do {
+ if (defaultAnswer != null)
+ out.print(prompt + " [" + defaultAnswer + "] >");
+ else
+ out.print(prompt);
+ out.flush();
+ result = getLine(reader);
+ if (result == null || result.length() == 0)
+ result = defaultAnswer;
+ } while (result == null);
+ return result;
+ }
+
+ // Not terribly efficient, but does the job.
+ // Works for reading a line from stdin or a file.
+ // Returns null on EOF. If EOF appears in the middle
+ // of a line, returns that line, then null on next call.
+ //
+ public static String getLine(InputStreamReader reader) {
+ StringBuffer b = new StringBuffer();
+ int c;
+ try {
+ while ((c = reader.read()) != -1 && c != '\n')
+ if (c != '\r')
+ b.append((char)c);
+ } catch (IOException ioe) {
+ c = -1;
+ }
+
+ if (c == -1 && b.length() == 0)
+ return null;
+ else
+ return b.toString();
+ }
+
+ public void run() throws DatabaseException {
+ long held;
+ int len = 0, locker;
+ int ret;
+ boolean did_get = false;
+ int lockid = 0;
+ InputStreamReader in = new InputStreamReader(System.in);
+ Vector locks = new Vector();
+
+ //
+ // Accept lock requests.
+ //
+ locker = dbenv.createLockerID();
+ for (held = 0;;) {
+ String opbuf = askForLine(in, System.out,
+ "Operation get/release", "get");
+ if (opbuf == null)
+ break;
+
+ try {
+ if (opbuf.equals("get") || opbuf.equals("vget")) {
+ // Acquire a lock.
+ String objbuf = askForLine(in, System.out,
+ "input object (text string) to lock> ", null);
+ if (objbuf == null)
+ break;
+
+ String lockbuf;
+ do {
+ lockbuf = askForLine(in, System.out,
+ "lock type read/write", "read");
+ if (lockbuf == null)
+ break;
+ len = lockbuf.length();
+ } while (len >= 1 &&
+ !lockbuf.equals("read") &&
+ !lockbuf.equals("write"));
+
+ LockRequestMode lock_type;
+ if (len <= 1 || lockbuf.equals("read"))
+ lock_type = LockRequestMode.READ;
+ else
+ lock_type = LockRequestMode.WRITE;
+
+ DatabaseEntry entry = new DatabaseEntry(objbuf.getBytes());
+
+ Lock lock;
+ if (opbuf.equals("get")) {
+ did_get = true;
+ lock = dbenv.getLock(locker, true, entry, lock_type);
+ } else {
+ LockRequest req = new LockRequest(
+ LockOperation.GET, lock_type, entry, null);
+ LockRequest[] reqs = { req };
+ dbenv.lockVector(locker, true, reqs);
+ lock = req.getLock();
+ System.out.println("Got lock: " + lock);
+ }
+ lockid = locks.size();
+ locks.addElement(lock);
+ } else {
+ // Release a lock.
+ String objbuf;
+ objbuf = askForLine(in, System.out,
+ "input lock to release> ", null);
+ if (objbuf == null)
+ break;
+
+ lockid = Integer.parseInt(objbuf, 16);
+ if (lockid < 0 || lockid >= locks.size()) {
+ System.out.println("Lock #" + lockid + " out of range");
+ continue;
+ }
+ did_get = false;
+ Lock lock = (Lock)locks.elementAt(lockid);
+ dbenv.putLock(lock);
+ }
+ System.out.println("Lock #" + lockid + " " +
+ (did_get ? "granted" : "released"));
+ held += did_get ? 1 : -1;
+ } catch (LockNotGrantedException lnge) {
+ System.err.println("Lock not granted");
+ } catch (DeadlockException de) {
+ System.err.println("LockExample: lock_" +
+ (did_get ? "get" : "put") +
+ ": returned DEADLOCK");
+ } catch (DatabaseException dbe) {
+ System.err.println("LockExample: lock_get: " + dbe.toString());
+ }
+ }
+ System.out.println();
+ System.out.println("Closing lock region " + String.valueOf(held) +
+ " locks held");
+ }
+
+ private static void usage() {
+ System.err.println("usage: LockExample [-u] [-h home] [-m maxlocks]");
+ System.exit(1);
+ }
+
+ public static void main(String[] argv) {
+ File home = LOCK_HOME;
+ boolean do_unlink = false;
+ int maxlocks = 0;
+
+ for (int i = 0; i < argv.length; ++i) {
+ if (argv[i].equals("-h")) {
+ if (++i >= argv.length)
+ usage();
+ home = new File(argv[i]);
+ } else if (argv[i].equals("-m")) {
+ if (++i >= argv.length)
+ usage();
+
+ try {
+ maxlocks = Integer.parseInt(argv[i]);
+ } catch (NumberFormatException nfe) {
+ usage();
+ }
+ } else if (argv[i].equals("-u")) {
+ do_unlink = true;
+ } else {
+ usage();
+ }
+ }
+
+ try {
+ LockExample app = new LockExample(home, maxlocks, do_unlink);
+ app.run();
+ app.close();
+ } catch (DatabaseException dbe) {
+ System.err.println(progname + ": " + dbe.toString());
+ } catch (Throwable t) {
+ System.err.println(progname + ": " + t.toString());
+ }
+ System.out.println("LockExample completed");
+ }
+}
diff --git a/examples_java/src/db/SequenceExample.java b/examples_java/src/db/SequenceExample.java
new file mode 100644
index 0000000..92f0984
--- /dev/null
+++ b/examples_java/src/db/SequenceExample.java
@@ -0,0 +1,92 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 1997-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package db;
+
+import com.sleepycat.db.*;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.PrintStream;
+
+class SequenceExample {
+ private static final int EXIT_SUCCESS = 0;
+ private static final int EXIT_FAILURE = 1;
+
+ public SequenceExample() {
+ }
+
+ public static void usage() {
+ System.out.println("usage: java " +
+ "db.SequenceExample [-r] [database]\n");
+ System.exit(EXIT_FAILURE);
+ }
+
+ public static void main(String[] argv) {
+ boolean removeExistingDatabase = false;
+ String databaseName = "access.db";
+
+ for (int i = 0; i < argv.length; i++) {
+ if (argv[i].equals("-r"))
+ removeExistingDatabase = true;
+ else if (argv[i].equals("-?"))
+ usage();
+ else if (argv[i].startsWith("-"))
+ usage();
+ else {
+ if ((argv.length - i) != 1)
+ usage();
+ databaseName = argv[i];
+ break;
+ }
+ }
+
+ try {
+ SequenceExample app = new SequenceExample();
+ app.run(removeExistingDatabase, databaseName);
+ } catch (DatabaseException dbe) {
+ System.err.println("SequenceExample: " + dbe.toString());
+ System.exit(EXIT_FAILURE);
+ } catch (FileNotFoundException fnfe) {
+ System.err.println("SequenceExample: " + fnfe.toString());
+ System.exit(EXIT_FAILURE);
+ }
+ System.exit(EXIT_SUCCESS);
+ }
+
+ public void run(boolean removeExistingDatabase, String databaseName)
+ throws DatabaseException, FileNotFoundException {
+
+ // Remove the previous database.
+ if (removeExistingDatabase)
+ new File(databaseName).delete();
+
+ // Create the database object.
+ // There is no environment for this simple example.
+ DatabaseConfig dbConfig = new DatabaseConfig();
+ dbConfig.setErrorStream(System.err);
+ dbConfig.setErrorPrefix("SequenceExample");
+ dbConfig.setType(DatabaseType.BTREE);
+ dbConfig.setAllowCreate(true);
+ Database table = new Database(databaseName, null, dbConfig);
+
+ SequenceConfig config = new SequenceConfig();
+ config.setAllowCreate(true);
+ DatabaseEntry key =
+ new DatabaseEntry("my_sequence".getBytes());
+ Sequence sequence = table.openSequence(null, key, config);
+
+ for (int i = 0; i < 10; i++) {
+ long seqnum = sequence.get(null, 1);
+ System.out.println("Got sequence number: " + seqnum);
+ }
+
+ sequence.close();
+ table.close();
+ }
+}
diff --git a/examples_java/src/db/TpcbExample.java b/examples_java/src/db/TpcbExample.java
new file mode 100644
index 0000000..883dca4
--- /dev/null
+++ b/examples_java/src/db/TpcbExample.java
@@ -0,0 +1,789 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 1997-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package db;
+
+import com.sleepycat.db.*;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.math.BigDecimal;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Random;
+import java.util.GregorianCalendar;
+
+//
+// This program implements a basic TPC/B driver program. To create the
+// TPC/B database, run with the -i (init) flag. The number of records
+// with which to populate the account, history, branch, and teller tables
+// is specified by the a, s, b, and t flags respectively. To run a TPC/B
+// test, use the n flag to indicate a number of transactions to run in
+// each thread and -T to specify the number of threads.
+//
+class TpcbExample {
+ public static final int TELLERS_PER_BRANCH = 10;
+ public static final int ACCOUNTS_PER_TELLER = 10000;
+ public static final int HISTORY_PER_BRANCH = 2592000;
+
+ //
+ // The default configuration that adheres to TPCB scaling rules requires
+ // nearly 3 GB of space. To avoid requiring that much space for testing,
+ // we set the parameters much lower. If you want to run a valid 10 TPS
+ // configuration, uncomment the VALID_SCALING configuration
+ //
+
+ // VALID_SCALING configuration
+ /*
+ public static final int ACCOUNTS = 1000000;
+ public static final int BRANCHES = 10;
+ public static final int TELLERS = 100;
+ public static final int HISTORY = 25920000;
+ */
+
+ // TINY configuration
+ /*
+ public static final int ACCOUNTS = 1000;
+ public static final int BRANCHES = 10;
+ public static final int TELLERS = 100;
+ public static final int HISTORY = 10000;
+ */
+
+ // Default configuration
+ public static final int ACCOUNTS = 100000;
+ public static final int BRANCHES = 10;
+ public static final int TELLERS = 100;
+ public static final int HISTORY = 259200;
+
+ public static final int HISTORY_LEN = 100;
+ public static final int RECLEN = 100;
+ public static final int BEGID = 1000000;
+
+ // used by random_id()
+ public static final int ACCOUNT = 0;
+ public static final int BRANCH = 1;
+ public static final int TELLER = 2;
+
+ public static boolean verbose = false;
+ public static final String progname = "TpcbExample"; // Program name.
+
+ Environment dbenv;
+ int accounts, branches, tellers, history;
+
+ public TpcbExample(File home,
+ int accounts, int branches, int tellers, int history,
+ int cachesize, boolean noSync)
+ throws DatabaseException, FileNotFoundException {
+
+ this.accounts = accounts;
+ this.branches = branches;
+ this.tellers = tellers;
+ this.history = history;
+
+ EnvironmentConfig config = new EnvironmentConfig();
+ config.setErrorStream(System.err);
+ config.setErrorPrefix(progname);
+ config.setLockDetectMode(LockDetectMode.DEFAULT);
+ config.setCacheSize(cachesize == 0 ? 4 * 1024 * 1024 : cachesize);
+ config.setTxnNoSync(noSync);
+ config.setLockDetectMode(LockDetectMode.DEFAULT);
+ config.setAllowCreate(true);
+
+ config.setInitializeCache(true);
+ config.setTransactional(true);
+ config.setInitializeLocking(true);
+ config.setInitializeLogging(true);
+
+ dbenv = new Environment(home, config);
+ }
+
+ public void close()
+ throws DatabaseException {
+
+ try {
+ if (dbenv != null)
+ dbenv.close();
+ } finally {
+ dbenv = null;
+ }
+ }
+
+ //
+ // Initialize the database to the number of accounts, branches,
+ // history records, and tellers given to the constructor.
+ //
+ public void populate() {
+ Database dbp = null;
+
+ int err;
+ int balance, idnum;
+ int end_anum, end_bnum, end_tnum;
+ int start_anum, start_bnum, start_tnum;
+ int h_nelem;
+
+ idnum = BEGID;
+ balance = 500000;
+
+ h_nelem = accounts;
+
+ try {
+ DatabaseConfig config = new DatabaseConfig();
+ config.setType(DatabaseType.HASH);
+ config.setHashNumElements(h_nelem);
+ config.setAllowCreate(true);
+ dbp = dbenv.openDatabase(null, "account", null, config);
+ } catch (Exception e1) {
+ // can be DatabaseException or FileNotFoundException
+ errExit(e1, "Open of account file failed");
+ }
+
+ start_anum = idnum;
+ populateTable(dbp, idnum, balance, h_nelem, "account");
+ idnum += h_nelem;
+ end_anum = idnum - 1;
+ try {
+ dbp.close();
+ } catch (DatabaseException e2) {
+ errExit(e2, "Account file close failed");
+ }
+
+ if (verbose)
+ System.out.println("Populated accounts: " +
+ String.valueOf(start_anum) + " - " +
+ String.valueOf(end_anum));
+
+ //
+ // Since the number of branches is very small, we want to use very
+ // small pages and only 1 key per page. This is the poor-man's way
+ // of getting key locking instead of page locking.
+ //
+ h_nelem = (int)branches;
+
+ try {
+ DatabaseConfig config = new DatabaseConfig();
+ config.setType(DatabaseType.HASH);
+ config.setHashNumElements(h_nelem);
+ config.setHashFillFactor(1);
+ config.setPageSize(512);
+ config.setAllowCreate(true);
+ dbp = dbenv.openDatabase(null, "branch", null, config);
+ } catch (Exception e3) {
+ // can be DatabaseException or FileNotFoundException
+ errExit(e3, "Branch file create failed");
+ }
+
+ start_bnum = idnum;
+ populateTable(dbp, idnum, balance, h_nelem, "branch");
+ idnum += h_nelem;
+ end_bnum = idnum - 1;
+
+ try {
+ dbp.close();
+ } catch (DatabaseException dbe4) {
+ errExit(dbe4, "Close of branch file failed");
+ }
+
+ if (verbose)
+ System.out.println("Populated branches: " +
+ String.valueOf(start_bnum) + " - " +
+ String.valueOf(end_bnum));
+
+ //
+ // In the case of tellers, we also want small pages, but we'll let
+ // the fill factor dynamically adjust itself.
+ //
+ h_nelem = (int)tellers;
+
+ try {
+ DatabaseConfig config = new DatabaseConfig();
+ config.setType(DatabaseType.HASH);
+ config.setHashNumElements(h_nelem);
+ config.setHashFillFactor(0);
+ config.setPageSize(512);
+ config.setAllowCreate(true);
+ dbp = dbenv.openDatabase(null, "teller", null, config);
+ } catch (Exception e5) {
+ // can be DatabaseException or FileNotFoundException
+ errExit(e5, "Teller file create failed");
+ }
+
+ start_tnum = idnum;
+ populateTable(dbp, idnum, balance, h_nelem, "teller");
+ idnum += h_nelem;
+ end_tnum = idnum - 1;
+
+ try {
+ dbp.close();
+ } catch (DatabaseException e6) {
+ errExit(e6, "Close of teller file failed");
+ }
+
+ if (verbose)
+ System.out.println("Populated tellers: " +
+ String.valueOf(start_tnum) + " - " +
+ String.valueOf(end_tnum));
+
+ try {
+ DatabaseConfig config = new DatabaseConfig();
+ config.setType(DatabaseType.RECNO);
+ config.setRecordLength(HISTORY_LEN);
+ config.setAllowCreate(true);
+ dbp = dbenv.openDatabase(null, "history", null, config);
+ } catch (Exception e7) {
+ // can be DatabaseException or FileNotFoundException
+ errExit(e7, "Create of history file failed");
+ }
+
+ populateHistory(dbp);
+
+ try {
+ dbp.close();
+ } catch (DatabaseException e8) {
+ errExit(e8, "Close of history file failed");
+ }
+ }
+
+ public void populateTable(Database dbp,
+ int start_id, int balance, int nrecs, String msg) {
+ Defrec drec = new Defrec();
+
+ DatabaseEntry kdbt = new DatabaseEntry(drec.data);
+ kdbt.setSize(4); // sizeof(int)
+ DatabaseEntry ddbt = new DatabaseEntry(drec.data);
+ ddbt.setSize(drec.data.length); // uses whole array
+
+ try {
+ for (int i = 0; i < nrecs; i++) {
+ kdbt.setRecordNumber(start_id + (int)i);
+ drec.set_balance(balance);
+ dbp.putNoOverwrite(null, kdbt, ddbt);
+ }
+ } catch (DatabaseException dbe) {
+ System.err.println("Failure initializing " + msg + " file: " +
+ dbe.toString());
+ System.exit(1);
+ }
+ }
+
+ public void populateHistory(Database dbp) {
+ Histrec hrec = new Histrec();
+ hrec.set_amount(10);
+
+ byte[] arr = new byte[4]; // sizeof(int)
+ int i;
+ DatabaseEntry kdbt = new DatabaseEntry(arr);
+ kdbt.setSize(arr.length);
+ DatabaseEntry ddbt = new DatabaseEntry(hrec.data);
+ ddbt.setSize(hrec.data.length);
+
+ try {
+ for (i = 1; i <= history; i++) {
+ kdbt.setRecordNumber(i);
+
+ hrec.set_aid(random_id(ACCOUNT));
+ hrec.set_bid(random_id(BRANCH));
+ hrec.set_tid(random_id(TELLER));
+
+ dbp.append(null, kdbt, ddbt);
+ }
+ } catch (DatabaseException dbe) {
+ errExit(dbe, "Failure initializing history file");
+ }
+ }
+
+ static Random rand = new Random();
+ public static int random_int(int lo, int hi) {
+ int t = rand.nextInt();
+ if (t < 0)
+ t = -t;
+ int ret = (int)(((double)t / ((double)(Integer.MAX_VALUE) + 1)) *
+ (hi - lo + 1));
+ ret += lo;
+ return (ret);
+ }
+
+ public int random_id(int type) {
+ int min, max, num;
+
+ max = min = BEGID;
+ num = accounts;
+ switch(type) {
+ case TELLER:
+ min += branches;
+ num = tellers;
+ // fallthrough
+ case BRANCH:
+ if (type == BRANCH)
+ num = branches;
+ min += accounts;
+ // fallthrough
+ case ACCOUNT:
+ max = min + num - 1;
+ }
+ return (random_int(min, max));
+ }
+
+ // The byte order is our choice.
+ //
+ static long get_int_in_array(byte[] array, int offset) {
+ return
+ ((0xff & array[offset + 0]) << 0) |
+ ((0xff & array[offset + 1]) << 8) |
+ ((0xff & array[offset + 2]) << 16) |
+ ((0xff & array[offset + 3]) << 24);
+ }
+
+ // Note: Value needs to be long to avoid sign extension
+ static void set_int_in_array(byte[] array, int offset, long value) {
+ array[offset + 0] = (byte)((value >> 0) & 0xff);
+ array[offset + 1] = (byte)((value >> 8) & 0xff);
+ array[offset + 2] = (byte)((value >> 16) & 0xff);
+ array[offset + 3] = (byte)((value >> 24) & 0xff);
+ }
+
+ // round 'd' to 'scale' digits, and return result as string
+ static String showRounded(double d, int scale) {
+ return new BigDecimal(d).
+ setScale(scale, BigDecimal.ROUND_HALF_DOWN).toString();
+ }
+
+ public void run(int ntxns, int threads) {
+ double gtps;
+ int txns, failed;
+ long curtime, starttime;
+ TxnThread[] txnList = new TxnThread[threads];
+ for (int i = 0; i < threads; i++)
+ txnList[i] = new TxnThread("Thread " + String.valueOf(i), ntxns);
+
+ starttime = (new Date()).getTime();
+ for (int i = 0; i < threads; i++)
+ txnList[i].start();
+ for (int i = 0; i < threads; i++)
+ try {
+ txnList[i].join();
+ } catch (Exception e1) {
+ errExit(e1, "join failed");
+ }
+
+ curtime = (new Date()).getTime();
+ txns = failed = 0;
+ for (int i = 0; i < threads; i++) {
+ txns += txnList[i].txns;
+ failed += txnList[i].failed;
+ }
+ gtps = (double)(txns - failed) /
+ ((curtime - starttime) / 1000.0);
+ System.out.print("\nTotal: " +
+ String.valueOf(txns) + " txns " +
+ String.valueOf(failed) + " failed ");
+ System.out.println(showRounded(gtps, 2) + " TPS");
+ }
+
+ class TxnThread extends Thread {
+ private int ntxns; /* Number of txns we were asked to run. */
+ public int txns, failed; /* Number that succeeded / failed. */
+ private Database adb, bdb, hdb, tdb;
+
+ public TxnThread(String name, int ntxns) {
+ super(name);
+ this.ntxns = ntxns;
+ }
+
+ public void run() {
+ double gtps, itps;
+ int n, ret;
+ long start_time, end_time;
+
+ //
+ // Open the database files.
+ //
+ int err;
+ try {
+ DatabaseConfig config = new DatabaseConfig();
+ config.setTransactional(true);
+ adb = dbenv.openDatabase(null, "account", null, config);
+ bdb = dbenv.openDatabase(null, "branch", null, config);
+ tdb = dbenv.openDatabase(null, "teller", null, config);
+ hdb = dbenv.openDatabase(null, "history", null, config);
+ } catch (DatabaseException dbe) {
+ TpcbExample.errExit(dbe, "Open of db files failed");
+ } catch (FileNotFoundException fnfe) {
+ TpcbExample.errExit(fnfe, "Open of db files failed, missing file");
+ }
+
+ start_time = (new Date()).getTime();
+ for (txns = n = ntxns, failed = 0; n-- > 0;)
+ if ((ret = txn()) != 0)
+ failed++;
+ end_time = (new Date()).getTime();
+ if (end_time == start_time)
+ end_time++;
+
+ System.out.println(getName() + ": " + (long)txns + " txns: " +
+ failed + " failed, " + TpcbExample.showRounded(
+ (txns - failed) / (double)(end_time - start_time), 2) + " TPS");
+
+ try {
+ adb.close();
+ bdb.close();
+ tdb.close();
+ hdb.close();
+ } catch (DatabaseException dbe2) {
+ TpcbExample.errExit(dbe2, "Close of db files failed");
+ }
+ }
+
+ //
+ // XXX Figure out the appropriate way to pick out IDs.
+ //
+ int txn() {
+ Cursor acurs = null;
+ Cursor bcurs = null;
+ Cursor hcurs = null;
+ Cursor tcurs = null;
+ Transaction t = null;
+
+ Defrec rec = new Defrec();
+ Histrec hrec = new Histrec();
+ int account, branch, teller;
+
+ DatabaseEntry d_dbt = new DatabaseEntry();
+ DatabaseEntry d_histdbt = new DatabaseEntry();
+ DatabaseEntry k_dbt = new DatabaseEntry();
+ DatabaseEntry k_histdbt = new DatabaseEntry();
+
+ account = TpcbExample.this.random_id(TpcbExample.ACCOUNT);
+ branch = TpcbExample.this.random_id(TpcbExample.BRANCH);
+ teller = TpcbExample.this.random_id(TpcbExample.TELLER);
+
+ // The history key will not actually be retrieved,
+ // but it does need to be set to something.
+ byte[] hist_key = new byte[4];
+ k_histdbt.setData(hist_key);
+ k_histdbt.setSize(4 /* == sizeof(int)*/);
+
+ byte[] key_bytes = new byte[4];
+ k_dbt.setData(key_bytes);
+ k_dbt.setSize(4 /* == sizeof(int)*/);
+
+ d_dbt.setData(rec.data);
+ d_dbt.setUserBuffer(rec.length(), true);
+
+ hrec.set_aid(account);
+ hrec.set_bid(branch);
+ hrec.set_tid(teller);
+ hrec.set_amount(10);
+ // Request 0 bytes since we're just positioning.
+ d_histdbt.setPartial(0, 0, true);
+
+ // START PER-TRANSACTION TIMING.
+ //
+ // Technically, TPCB requires a limit on response time, you only
+ // get to count transactions that complete within 2 seconds.
+ // That's not an issue for this sample application -- regardless,
+ // here's where the transaction begins.
+ try {
+ t = dbenv.beginTransaction(null, null);
+
+ acurs = adb.openCursor(t, null);
+ bcurs = bdb.openCursor(t, null);
+ tcurs = tdb.openCursor(t, null);
+ hcurs = hdb.openCursor(t, null);
+
+ // Account record
+ k_dbt.setRecordNumber(account);
+ if (acurs.getSearchKey(k_dbt, d_dbt, null) != OperationStatus.SUCCESS)
+ throw new Exception("acurs get failed");
+ rec.set_balance(rec.get_balance() + 10);
+ acurs.putCurrent(d_dbt);
+
+ // Branch record
+ k_dbt.setRecordNumber(branch);
+ if (bcurs.getSearchKey(k_dbt, d_dbt, null) != OperationStatus.SUCCESS)
+ throw new Exception("bcurs get failed");
+ rec.set_balance(rec.get_balance() + 10);
+ bcurs.putCurrent(d_dbt);
+
+ // Teller record
+ k_dbt.setRecordNumber(teller);
+ if (tcurs.getSearchKey(k_dbt, d_dbt, null) != OperationStatus.SUCCESS)
+ throw new Exception("ccurs get failed");
+ rec.set_balance(rec.get_balance() + 10);
+ tcurs.putCurrent(d_dbt);
+
+ // History record
+ d_histdbt.setPartial(0, 0, false);
+ d_histdbt.setData(hrec.data);
+ d_histdbt.setUserBuffer(hrec.length(), true);
+ if (hdb.append(t, k_histdbt, d_histdbt) != OperationStatus.SUCCESS)
+ throw new DatabaseException("put failed");
+
+ acurs.close();
+ acurs = null;
+ bcurs.close();
+ bcurs = null;
+ tcurs.close();
+ tcurs = null;
+ hcurs.close();
+ hcurs = null;
+
+ // null out t in advance; if the commit fails,
+ // we don't want to abort it in the catch clause.
+ Transaction tmptxn = t;
+ t = null;
+ tmptxn.commit();
+
+ // END TIMING
+ return (0);
+ } catch (Exception e) {
+ try {
+ if (acurs != null)
+ acurs.close();
+ if (bcurs != null)
+ bcurs.close();
+ if (tcurs != null)
+ tcurs.close();
+ if (hcurs != null)
+ hcurs.close();
+ if (t != null)
+ t.abort();
+ } catch (DatabaseException dbe) {
+ // not much we can do here.
+ }
+
+ if (TpcbExample.this.verbose) {
+ System.out.println("Transaction A=" + String.valueOf(account) +
+ " B=" + String.valueOf(branch) +
+ " T=" + String.valueOf(teller) +
+ " failed");
+ System.out.println("Reason: " + e.toString());
+ }
+ return (-1);
+ }
+ }
+ }
+
+ private static void usage() {
+ System.err.println(
+ "usage: TpcbExample [-fiv] [-a accounts] [-b branches]\n" +
+ " [-c cachesize] [-h home] [-n transactions]\n" +
+ " [-T threads] [-S seed] [-s history] [-t tellers]");
+ System.exit(1);
+ }
+
+ private static void invarg(String str) {
+ System.err.println("TpcbExample: invalid argument: " + str);
+ System.exit(1);
+ }
+
+ public static void errExit(Exception err, String s) {
+ System.err.print(progname + ": ");
+ if (s != null) {
+ System.err.print(s + ": ");
+ }
+ System.err.println(err.toString());
+ System.exit(1);
+ }
+
+ public static void main(String[] argv) throws java.io.IOException {
+ File home = new File("TESTDIR");
+ int accounts = ACCOUNTS;
+ int branches = BRANCHES;
+ int tellers = TELLERS;
+ int history = HISTORY;
+ int threads = 1;
+ int mpool = 0;
+ int ntxns = 0;
+ boolean iflag = false;
+ boolean txn_no_sync = false;
+ long seed = (new GregorianCalendar()).get(Calendar.SECOND);
+
+ for (int i = 0; i < argv.length; ++i) {
+ if (argv[i].equals("-a")) {
+ // Number of account records
+ if ((accounts = Integer.parseInt(argv[++i])) <= 0)
+ invarg(argv[i]);
+ } else if (argv[i].equals("-b")) {
+ // Number of branch records
+ if ((branches = Integer.parseInt(argv[++i])) <= 0)
+ invarg(argv[i]);
+ } else if (argv[i].equals("-c")) {
+ // Cachesize in bytes
+ if ((mpool = Integer.parseInt(argv[++i])) <= 0)
+ invarg(argv[i]);
+ } else if (argv[i].equals("-f")) {
+ // Fast mode: no txn sync.
+ txn_no_sync = true;
+ } else if (argv[i].equals("-h")) {
+ // DB home.
+ home = new File(argv[++i]);
+ } else if (argv[i].equals("-i")) {
+ // Initialize the test.
+ iflag = true;
+ } else if (argv[i].equals("-n")) {
+ // Number of transactions
+ if ((ntxns = Integer.parseInt(argv[++i])) <= 0)
+ invarg(argv[i]);
+ } else if (argv[i].equals("-S")) {
+ // Random number seed.
+ seed = Long.parseLong(argv[++i]);
+ if (seed <= 0)
+ invarg(argv[i]);
+ } else if (argv[i].equals("-s")) {
+ // Number of history records
+ if ((history = Integer.parseInt(argv[++i])) <= 0)
+ invarg(argv[i]);
+ } else if (argv[i].equals("-T")) {
+ // Number of threads
+ if ((threads = Integer.parseInt(argv[++i])) <= 0)
+ invarg(argv[i]);
+ } else if (argv[i].equals("-t")) {
+ // Number of teller records
+ if ((tellers = Integer.parseInt(argv[++i])) <= 0)
+ invarg(argv[i]);
+ } else if (argv[i].equals("-v")) {
+ // Verbose option.
+ verbose = true;
+ } else {
+ usage();
+ }
+ }
+
+ rand.setSeed((int)seed);
+
+ // Initialize the database environment.
+ // Must be done in within a try block.
+ //
+ TpcbExample app = null;
+ try {
+ app = new TpcbExample(home, accounts, branches, tellers, history,
+ mpool, iflag || txn_no_sync);
+ } catch (Exception e1) {
+ errExit(e1, "initializing environment failed");
+ }
+
+ if (verbose)
+ System.out.println((long)accounts + " Accounts, " +
+ String.valueOf(branches) + " Branches, " +
+ String.valueOf(tellers) + " Tellers, " +
+ String.valueOf(history) + " History");
+
+ if (iflag) {
+ if (ntxns != 0)
+ usage();
+ app.populate();
+ } else {
+ if (ntxns == 0)
+ usage();
+ app.run(ntxns, threads);
+ }
+
+ // Shut down the application.
+
+ try {
+ app.close();
+ } catch (DatabaseException dbe2) {
+ errExit(dbe2, "appexit failed");
+ }
+
+ System.exit(0);
+ }
+};
+
+// Simulate the following C struct:
+// struct Defrec {
+// u_int32_t id;
+// u_int32_t balance;
+// u_int8_t pad[RECLEN - sizeof(int) - sizeof(int)];
+// };
+
+class Defrec {
+ public Defrec() {
+ data = new byte[TpcbExample.RECLEN];
+ }
+
+ public int length() {
+ return TpcbExample.RECLEN;
+ }
+
+ public long get_id() {
+ return TpcbExample.get_int_in_array(data, 0);
+ }
+
+ public void set_id(long value) {
+ TpcbExample.set_int_in_array(data, 0, value);
+ }
+
+ public long get_balance() {
+ return TpcbExample.get_int_in_array(data, 4);
+ }
+
+ public void set_balance(long value) {
+ TpcbExample.set_int_in_array(data, 4, value);
+ }
+
+ static {
+ Defrec d = new Defrec();
+ d.set_balance(500000);
+ }
+
+ public byte[] data;
+}
+
+// Simulate the following C struct:
+// struct Histrec {
+// u_int32_t aid;
+// u_int32_t bid;
+// u_int32_t tid;
+// u_int32_t amount;
+// u_int8_t pad[RECLEN - 4 * sizeof(u_int32_t)];
+// };
+
+class Histrec {
+ public Histrec() {
+ data = new byte[TpcbExample.RECLEN];
+ }
+
+ public int length() {
+ return TpcbExample.RECLEN;
+ }
+
+ public long get_aid() {
+ return TpcbExample.get_int_in_array(data, 0);
+ }
+
+ public void set_aid(long value) {
+ TpcbExample.set_int_in_array(data, 0, value);
+ }
+
+ public long get_bid() {
+ return TpcbExample.get_int_in_array(data, 4);
+ }
+
+ public void set_bid(long value) {
+ TpcbExample.set_int_in_array(data, 4, value);
+ }
+
+ public long get_tid() {
+ return TpcbExample.get_int_in_array(data, 8);
+ }
+
+ public void set_tid(long value) {
+ TpcbExample.set_int_in_array(data, 8, value);
+ }
+
+ public long get_amount() {
+ return TpcbExample.get_int_in_array(data, 12);
+ }
+
+ public void set_amount(long value) {
+ TpcbExample.set_int_in_array(data, 12, value);
+ }
+
+ public byte[] data;
+}
diff --git a/examples_java/src/db/repquote/RepConfig.java b/examples_java/src/db/repquote/RepConfig.java
new file mode 100644
index 0000000..6f29d43
--- /dev/null
+++ b/examples_java/src/db/repquote/RepConfig.java
@@ -0,0 +1,111 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2001-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package db.repquote;
+
+import java.util.Vector;
+
+import com.sleepycat.db.ReplicationHostAddress;
+import com.sleepycat.db.ReplicationManagerAckPolicy;
+import com.sleepycat.db.ReplicationManagerStartPolicy;
+import com.sleepycat.db.ReplicationManagerSiteInfo;
+
+public class RepConfig
+{
+ /* Constant values used in the RepQuote application. */
+ public static final String progname = "RepQuoteExample";
+ public static final int CACHESIZE = 10 * 1024 * 1024;
+ public static final int SLEEPTIME = 5000;
+
+ /* Member variables containing configuration information. */
+ public ReplicationManagerAckPolicy ackPolicy;
+ public boolean bulk; /* Whether bulk transfer should be performed. */
+ public String home; /* The home directory for rep files. */
+ public Vector otherHosts; /* Stores an optional set of "other" hosts. */
+ public int priority; /* Priority within the replication group. */
+ public ReplicationManagerStartPolicy startPolicy;
+ public ReplicationHostAddress thisHost; /* Host address to listen to. */
+ /* Optional value specifying the # of sites in the replication group. */
+ public int totalSites;
+ public boolean verbose;
+
+ /* Member variables used internally. */
+ private int currOtherHost;
+ private boolean gotListenAddress;
+
+ public RepConfig()
+ {
+ startPolicy = ReplicationManagerStartPolicy.REP_ELECTION;
+ home = "";
+ gotListenAddress = false;
+ totalSites = 0;
+ priority = 100;
+ verbose = false;
+ currOtherHost = 0;
+ thisHost = new ReplicationHostAddress();
+ otherHosts = new Vector();
+ ackPolicy = ReplicationManagerAckPolicy.QUORUM;
+ bulk = false;
+ }
+
+ public java.io.File getHome()
+ {
+ return new java.io.File(home);
+ }
+
+ public void setThisHost(String host, int port)
+ {
+ gotListenAddress = true;
+ thisHost.port = port;
+ thisHost.host = host;
+ }
+
+ public ReplicationHostAddress getThisHost()
+ {
+ if (!gotListenAddress)
+ System.err.println("Warning: no host specified, returning default.");
+ return thisHost;
+ }
+
+ public boolean gotListenAddress() {
+ return gotListenAddress;
+ }
+
+ public void addOtherHost(String host, int port, boolean peer)
+ {
+ ReplicationHostAddress newInfo =
+ new ReplicationHostAddress(host, port);
+ RepRemoteHost newHost = new RepRemoteHost(newInfo, peer);
+ otherHosts.add(newHost);
+ }
+
+ public RepRemoteHost getFirstOtherHost()
+ {
+ currOtherHost = 0;
+ if (otherHosts.size() == 0)
+ return null;
+ return (RepRemoteHost)otherHosts.get(currOtherHost);
+ }
+
+ public RepRemoteHost getNextOtherHost()
+ {
+ currOtherHost++;
+ if (currOtherHost >= otherHosts.size())
+ return null;
+ return (RepRemoteHost)otherHosts.get(currOtherHost);
+ }
+
+ public RepRemoteHost getOtherHost(int i)
+ {
+ if (i >= otherHosts.size())
+ return null;
+ return (RepRemoteHost)otherHosts.get(i);
+ }
+
+}
+
diff --git a/examples_java/src/db/repquote/RepQuoteEnvironment.java b/examples_java/src/db/repquote/RepQuoteEnvironment.java
new file mode 100644
index 0000000..af475b6
--- /dev/null
+++ b/examples_java/src/db/repquote/RepQuoteEnvironment.java
@@ -0,0 +1,59 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 1997-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package db.repquote;
+
+import com.sleepycat.db.*;
+
+/*
+ * A simple wrapper class, that facilitates storing some
+ * custom information with an Environment object.
+ * The information is used by the Replication callback (handleEvent).
+ */
+public class RepQuoteEnvironment extends Environment
+{
+ private boolean appFinished;
+ private boolean inClientSync;
+ private boolean isMaster;
+
+ public RepQuoteEnvironment(final java.io.File host,
+ EnvironmentConfig config)
+ throws DatabaseException, java.io.FileNotFoundException
+ {
+ super(host, config);
+ appFinished = false;
+ inClientSync = false;
+ isMaster = false;
+ }
+
+ boolean getAppFinished()
+ {
+ return appFinished;
+ }
+ public void setAppFinished(boolean appFinished)
+ {
+ this.appFinished = appFinished;
+ }
+ boolean getInClientSync()
+ {
+ return inClientSync;
+ }
+ public void setInClientSync(boolean inClientSync)
+ {
+ this.inClientSync = inClientSync;
+ }
+ boolean getIsMaster()
+ {
+ return isMaster;
+ }
+ public void setIsMaster(boolean isMaster)
+ {
+ this.isMaster = isMaster;
+ }
+}
+
diff --git a/examples_java/src/db/repquote/RepQuoteExample.java b/examples_java/src/db/repquote/RepQuoteExample.java
new file mode 100644
index 0000000..2c828c9
--- /dev/null
+++ b/examples_java/src/db/repquote/RepQuoteExample.java
@@ -0,0 +1,669 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 1997-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package db.repquote;
+
+import java.io.FileNotFoundException;
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.io.IOException;
+import java.lang.Thread;
+import java.lang.InterruptedException;
+
+import com.sleepycat.db.*;
+import db.repquote.RepConfig;
+
+/**
+ * RepQuoteExample is a simple but complete demonstration of a replicated
+ * application. The application is a mock stock ticker. The master accepts a
+ * stock symbol and an numerical value as input, and stores this information
+ * into a replicated database; either master or clients can display the
+ * contents of the database.
+ * <p>
+ * The options to start a given replication node are:
+ * <pre>
+ * -h home (required; h stands for home directory)
+ * -l host:port (required; l stands for local)
+ * -C or M (optional; start up as client or master)
+ * -r host:port (optional; r stands for remote; any number of these may
+ * be specified)
+ * -R host:port (optional; R stands for remote peer; only one of these may
+ * be specified)
+ * -a all|quorum (optional; a stands for ack policy)
+ * -b (optional; b stands for bulk)
+ * -n nsites (optional; number of sites in replication group; defaults to 0
+ * to try to dynamically compute nsites)
+ * -p priority (optional; defaults to 100)
+ * -v (optional; v stands for verbose)
+ * </pre>
+ * <p>
+ * A typical session begins with a command such as the following to start a
+ * master:
+ *
+ * <pre>
+ * java db.repquote.RepQuoteExample -M -h dir1 -l localhost:6000
+ * </pre>
+ *
+ * and several clients:
+ *
+ * <pre>
+ * java db.repquote.RepQuoteExample -C -h dir2
+ * -l localhost:6001 -r localhost:6000
+ * java db.repquote.RepQuoteExample -C -h dir3
+ * -l localhost:6002 -r localhost:6000
+ * java db.repquote.RepQuoteExample -C -h dir4
+ * -l localhost:6003 -r localhost:6000
+ * </pre>
+ *
+ * <p>
+ * Each process is a member of a DB replication group. The sample application
+ * expects the following commands to stdin:
+ * <ul>
+ * <li>NEWLINE -- print all the stocks held in the database</li>
+ * <li>quit -- shutdown this node</li>
+ * <li>exit -- shutdown this node</li>
+ * <li>stock_symbol number -- enter this stock and number into the
+ * database</li>
+ * </ul>
+ */
+
+public class RepQuoteExample
+{
+ private RepConfig appConfig;
+ private RepQuoteEnvironment dbenv;
+ private CheckpointThread ckpThr;
+ private LogArchiveThread lgaThr;
+
+ public static void usage()
+ {
+ System.err.println("usage: " + RepConfig.progname +
+ " -h home -l host:port [-CM][-r host:port][-R host:port]\n" +
+ " [-a all|quorum][-b][-n nsites][-p priority][-v]");
+
+ System.err.println(
+ "\t -h home (required; h stands for home directory)\n" +
+ "\t -l host:port (required; l stands for local)\n" +
+ "\t -C or -M (optional; start up as client or master)\n" +
+ "\t -r host:port (optional; r stands for remote; any number " +
+ "of these\n" +
+ "\t may be specified)\n" +
+ "\t -R host:port (optional; R stands for remote peer; only " +
+ "one of\n" +
+ "\t these may be specified)\n" +
+ "\t -a all|quorum (optional; a stands for ack policy)\n" +
+ "\t -b (optional; b stands for bulk)\n" +
+ "\t -n nsites (optional; number of sites in replication " +
+ "group; defaults\n" +
+ "\t to 0 to try to dynamically compute nsites)\n" +
+ "\t -p priority (optional; defaults to 100)\n" +
+ "\t -v (optional; v stands for verbose)\n");
+
+ System.exit(1);
+ }
+
+ public static void main(String[] argv)
+ throws Exception
+ {
+ RepConfig config = new RepConfig();
+ boolean isPeer;
+ String tmpHost;
+ int tmpPort = 0;
+
+ /* Extract the command line parameters. */
+ for (int i = 0; i < argv.length; i++)
+ {
+ isPeer = false;
+ if (argv[i].compareTo("-a") == 0) {
+ if (i == argv.length - 1)
+ usage();
+ i++;
+ if (argv[i].equals("all"))
+ config.ackPolicy = ReplicationManagerAckPolicy.ALL;
+ else if (!argv[i].equals("quorum"))
+ usage();
+ } else if (argv[i].compareTo("-b") == 0)
+ config.bulk = true;
+ else if (argv[i].compareTo("-C") == 0) {
+ config.startPolicy = ReplicationManagerStartPolicy.REP_CLIENT;
+ } else if (argv[i].compareTo("-h") == 0) {
+ if (i == argv.length - 1)
+ usage();
+ /* home - a string arg. */
+ i++;
+ config.home = argv[i];
+ } else if (argv[i].compareTo("-l") == 0) {
+ if (i == argv.length - 1)
+ usage();
+ /* "local" should be host:port. */
+ i++;
+ String[] words = argv[i].split(":");
+ if (words.length != 2) {
+ System.err.println(
+ "Invalid host specification host:port needed.");
+ usage();
+ }
+ try {
+ tmpPort = Integer.parseInt(words[1]);
+ } catch (NumberFormatException nfe) {
+ System.err.println("Invalid host specification, " +
+ "could not parse port number.");
+ usage();
+ }
+ config.setThisHost(words[0], tmpPort);
+ } else if (argv[i].compareTo("-M") == 0) {
+ config.startPolicy = ReplicationManagerStartPolicy.REP_MASTER;
+ } else if (argv[i].compareTo("-n") == 0) {
+ if (i == argv.length - 1)
+ usage();
+ i++;
+ config.totalSites = Integer.parseInt(argv[i]);
+ } else if (argv[i].compareTo("-p") == 0) {
+ if (i == argv.length - 1)
+ usage();
+ i++;
+ config.priority = Integer.parseInt(argv[i]);
+ } else if (argv[i].compareTo("-R") == 0 ||
+ argv[i].compareTo("-r") == 0) {
+ if (i == argv.length - 1)
+ usage();
+ if (argv[i].equals("-R"))
+ isPeer = true;
+ i++;
+ String[] words = argv[i].split(":");
+ if (words.length != 2) {
+ System.err.println(
+ "Invalid host specification host:port needed.");
+ usage();
+ }
+ try {
+ tmpPort = Integer.parseInt(words[1]);
+ } catch (NumberFormatException nfe) {
+ System.err.println("Invalid host specification, " +
+ "could not parse port number.");
+ usage();
+ }
+ config.addOtherHost(words[0], tmpPort, isPeer);
+ } else if (argv[i].compareTo("-v") == 0) {
+ config.verbose = true;
+ } else {
+ System.err.println("Unrecognized option: " + argv[i]);
+ usage();
+ }
+
+ }
+
+ /* Error check command line. */
+ if ((!config.gotListenAddress()) || config.home.length() == 0)
+ usage();
+
+ RepQuoteExample runner = null;
+ try {
+ runner = new RepQuoteExample();
+ runner.init(config);
+
+ /* Sleep to give ourselves time to find a master. */
+ //try {
+ // Thread.sleep(5000);
+ //} catch (InterruptedException e) {}
+
+ runner.doloop();
+ runner.terminate();
+ } catch (DatabaseException dbe) {
+ System.err.println("Caught an exception during " +
+ "initialization or processing: " + dbe);
+ if (runner != null)
+ runner.terminate();
+ }
+ } /* End main. */
+
+ public RepQuoteExample()
+ throws DatabaseException
+ {
+ appConfig = null;
+ dbenv = null;
+ }
+
+ public int init(RepConfig config)
+ throws DatabaseException
+ {
+ int ret = 0;
+ appConfig = config;
+ EnvironmentConfig envConfig = new EnvironmentConfig();
+ envConfig.setErrorStream(System.err);
+ envConfig.setErrorPrefix(RepConfig.progname);
+
+ envConfig.setReplicationManagerLocalSite(appConfig.getThisHost());
+ for (RepRemoteHost host = appConfig.getFirstOtherHost();
+ host != null; host = appConfig.getNextOtherHost()){
+ envConfig.replicationManagerAddRemoteSite(
+ host.getAddress(), host.isPeer());
+ }
+ if (appConfig.totalSites > 0)
+ envConfig.setReplicationNumSites(appConfig.totalSites);
+
+ /*
+ * Set replication group election priority for this environment.
+ * An election first selects the site with the most recent log
+ * records as the new master. If multiple sites have the most
+ * recent log records, the site with the highest priority value
+ * is selected as master.
+ */
+ envConfig.setReplicationPriority(appConfig.priority);
+
+ envConfig.setCacheSize(RepConfig.CACHESIZE);
+ envConfig.setTxnNoSync(true);
+
+ envConfig.setEventHandler(new RepQuoteEventHandler());
+
+ /*
+ * Set the policy that determines how master and client sites
+ * handle acknowledgement of replication messages needed for
+ * permanent records. The default policy of "quorum" requires only
+ * a quorum of electable peers sufficient to ensure a permanent
+ * record remains durable if an election is held. The "all" option
+ * requires all clients to acknowledge a permanent replication
+ * message instead.
+ */
+ envConfig.setReplicationManagerAckPolicy(appConfig.ackPolicy);
+
+ /*
+ * Set the threshold for the minimum and maximum time the client
+ * waits before requesting retransmission of a missing message.
+ * Base these values on the performance and load characteristics
+ * of the master and client host platforms as well as the round
+ * trip message time.
+ */
+ envConfig.setReplicationRequestMin(20000);
+ envConfig.setReplicationRequestMax(500000);
+
+ /*
+ * Configure deadlock detection to ensure that any deadlocks
+ * are broken by having one of the conflicting lock requests
+ * rejected. DB_LOCK_DEFAULT uses the lock policy specified
+ * at environment creation time or DB_LOCK_RANDOM if none was
+ * specified.
+ */
+ envConfig.setLockDetectMode(LockDetectMode.DEFAULT);
+
+ envConfig.setAllowCreate(true);
+ envConfig.setRunRecovery(true);
+ envConfig.setThreaded(true);
+ envConfig.setInitializeReplication(true);
+ envConfig.setInitializeLocking(true);
+ envConfig.setInitializeLogging(true);
+ envConfig.setInitializeCache(true);
+ envConfig.setTransactional(true);
+ envConfig.setVerboseReplication(appConfig.verbose);
+ try {
+ dbenv = new RepQuoteEnvironment(appConfig.getHome(), envConfig);
+ } catch(FileNotFoundException e) {
+ System.err.println("FileNotFound exception: " + e);
+ System.err.println(
+ "Ensure that the environment directory is pre-created.");
+ ret = 1;
+ }
+
+ if (appConfig.bulk)
+ dbenv.setReplicationConfig(ReplicationConfig.BULK, true);
+
+ /*
+ * Configure heartbeat timeouts so that repmgr monitors the
+ * health of the TCP connection. Master sites broadcast a heartbeat
+ * at the frequency specified by the DB_REP_HEARTBEAT_SEND timeout.
+ * Client sites wait for message activity the length of the
+ * DB_REP_HEARTBEAT_MONITOR timeout before concluding that the
+ * connection to the master is lost. The DB_REP_HEARTBEAT_MONITOR
+ * timeout should be longer than the DB_REP_HEARTBEAT_SEND timeout.
+ */
+ dbenv.setReplicationTimeout(ReplicationTimeoutType.HEARTBEAT_SEND,
+ 5000000);
+ dbenv.setReplicationTimeout(ReplicationTimeoutType.HEARTBEAT_MONITOR,
+ 10000000);
+
+ /* The following base replication features may also be useful to your
+ * application. See Berkeley DB documentation for more details.
+ * - Master leases: Provide stricter consistency for data reads
+ * on a master site.
+ * - Timeouts: Customize the amount of time Berkeley DB waits
+ * for such things as an election to be concluded or a master
+ * lease to be granted.
+ * - Delayed client synchronization: Manage the master site's
+ * resources by spreading out resource-intensive client
+ * synchronizations.
+ * - Blocked client operations: Return immediately with an error
+ * instead of waiting indefinitely if a client operation is
+ * blocked by an ongoing client synchronization.
+ *
+ * The following repmgr features may also be useful to your
+ * application. See Berkeley DB documentation for more details.
+ * - Two-site strict majority rule - In a two-site replication
+ * group, require both sites to be available to elect a new
+ * master.
+ * - Timeouts - Customize the amount of time repmgr waits
+ * for such things as waiting for acknowledgements or attempting
+ * to reconnect to other sites.
+ * - Site list - return a list of sites currently known to repmgr.
+ */
+
+ /* Start checkpoint and log archive support threads. */
+ ckpThr = new CheckpointThread(dbenv);
+ ckpThr.start();
+ lgaThr = new LogArchiveThread(dbenv, envConfig);
+ lgaThr.start();
+
+ /* Start replication manager. */
+ dbenv.replicationManagerStart(3, appConfig.startPolicy);
+
+ return ret;
+ }
+
+ public int doloop()
+ throws DatabaseException
+ {
+ Database db = null;
+
+ for (;;)
+ {
+ if (db == null) {
+ DatabaseConfig dbconf = new DatabaseConfig();
+ dbconf.setType(DatabaseType.BTREE);
+ if (dbenv.getIsMaster()) {
+ /*
+ * Open database allowing create only if this is a master
+ * database. A client database uses polling to attempt
+ * to open the database without allowing create until
+ * it is successful.
+ *
+ * This polling logic for allowing create can be
+ * simplified under some circumstances. For example, if
+ * the application can be sure a database is already
+ * there, it would never need to open it allowing create.
+ */
+ dbconf.setAllowCreate(true);
+ }
+ dbconf.setTransactional(true);
+
+ try {
+ db = dbenv.openDatabase
+ (null, RepConfig.progname, null, dbconf);
+ } catch (java.io.FileNotFoundException e) {
+ System.err.println("no stock database available yet.");
+ if (db != null) {
+ db.close(true);
+ db = null;
+ }
+ try {
+ Thread.sleep(RepConfig.SLEEPTIME);
+ } catch (InterruptedException ie) {}
+ continue;
+ }
+ }
+
+ BufferedReader stdin =
+ new BufferedReader(new InputStreamReader(System.in));
+
+ /* Listen for input, and add it to the database. */
+ System.out.print("QUOTESERVER");
+ if (!dbenv.getIsMaster())
+ System.out.print("(read-only)");
+ System.out.print("> ");
+ System.out.flush();
+ String nextline = null;
+ try {
+ nextline = stdin.readLine();
+ } catch (IOException ioe) {
+ System.err.println("Unable to get data from stdin");
+ break;
+ }
+ String[] words = nextline.split("\\s");
+
+ /* A blank line causes the DB to be dumped to stdout. */
+ if (words.length == 0 ||
+ (words.length == 1 && words[0].length() == 0)) {
+ try {
+ if (dbenv.getInClientSync())
+ System.err.println(
+ "Cannot read data during client initialization - please try again.");
+ else
+ printStocks(db);
+ } catch (DeadlockException de) {
+ continue;
+ } catch (DatabaseException e) {
+ /*
+ * This could be DB_REP_HANDLE_DEAD, which
+ * should close the database and continue.
+ */
+ System.err.println("Got db exception reading replication" +
+ "DB: " + e);
+ System.err.println("Expected if it was due to a dead " +
+ "replication handle, otherwise an unexpected error.");
+ db.close(true); /* Close no sync. */
+ db = null;
+ continue;
+ }
+ continue;
+ }
+
+ if (words.length == 1 &&
+ (words[0].compareToIgnoreCase("quit") == 0 ||
+ words[0].compareToIgnoreCase("exit") == 0)) {
+ dbenv.setAppFinished(true);
+ break;
+ } else if (words.length != 2) {
+ System.err.println("Format: TICKER VALUE");
+ continue;
+ }
+
+ if (!dbenv.getIsMaster()) {
+ System.err.println("Can't update client.");
+ continue;
+ }
+
+ DatabaseEntry key = new DatabaseEntry(words[0].getBytes());
+ DatabaseEntry data = new DatabaseEntry(words[1].getBytes());
+
+ db.put(null, key, data);
+ }
+ if (db != null)
+ db.close(true);
+ return 0;
+ }
+
+ public void terminate()
+ throws DatabaseException
+ {
+ /* Wait for checkpoint and log archive threads to finish. */
+ try {
+ lgaThr.join();
+ ckpThr.join();
+ } catch (Exception e1) {
+ System.err.println("Support thread join failed.");
+ }
+
+ /*
+ * We have used the DB_TXN_NOSYNC environment flag for improved
+ * performance without the usual sacrifice of transactional durability,
+ * as discussed in the "Transactional guarantees" page of the Reference
+ * Guide: if one replication site crashes, we can expect the data to
+ * exist at another site. However, in case we shut down all sites
+ * gracefully, we push out the end of the log here so that the most
+ * recent transactions don't mysteriously disappear.
+ */
+ dbenv.logFlush(null);
+
+ dbenv.close();
+ }
+
+ /*
+ * void return type since error conditions are propogated
+ * via exceptions.
+ */
+ private void printStocks(Database db)
+ throws DeadlockException, DatabaseException
+ {
+ Cursor dbc = db.openCursor(null, null);
+
+ System.out.println("\tSymbol\tPrice");
+ System.out.println("\t======\t=====");
+
+ DatabaseEntry key = new DatabaseEntry();
+ DatabaseEntry data = new DatabaseEntry();
+ OperationStatus ret;
+ for (ret = dbc.getFirst(key, data, LockMode.DEFAULT);
+ ret == OperationStatus.SUCCESS;
+ ret = dbc.getNext(key, data, LockMode.DEFAULT)) {
+ String keystr = new String
+ (key.getData(), key.getOffset(), key.getSize());
+ String datastr = new String
+ (data.getData(), data.getOffset(), data.getSize());
+ System.out.println("\t"+keystr+"\t"+datastr);
+
+ }
+ dbc.close();
+ }
+
+ /*
+ * Implemention of EventHandler interface to handle the Berkeley DB events
+ * we are interested in receiving.
+ */
+ private /* internal */
+ class RepQuoteEventHandler extends EventHandlerAdapter {
+ public void handleRepClientEvent()
+ {
+ dbenv.setIsMaster(false);
+ dbenv.setInClientSync(true);
+ }
+ public void handleRepMasterEvent()
+ {
+ dbenv.setIsMaster(true);
+ dbenv.setInClientSync(false);
+ }
+ public void handleRepNewMasterEvent()
+ {
+ dbenv.setInClientSync(true);
+ }
+ public void handleRepPermFailedEvent()
+ {
+ /*
+ * Did not get enough acks to guarantee transaction
+ * durability based on the configured ack policy. This
+ * transaction will be flushed to the master site's
+ * local disk storage for durability.
+ */
+ System.err.println(
+ "Insufficient acknowledgements to guarantee transaction durability.");
+ }
+ public void handleRepStartupDoneEvent()
+ {
+ dbenv.setInClientSync(false);
+ }
+ }
+} /* End RepQuoteEventHandler class. */
+
+/*
+ * This is a very simple thread that performs checkpoints at a fixed
+ * time interval. For a master site, the time interval is one minute
+ * plus the duration of the checkpoint_delay timeout (30 seconds by
+ * default.) For a client site, the time interval is one minute.
+ */
+class CheckpointThread extends Thread {
+ private RepQuoteEnvironment myEnv = null;
+
+ public CheckpointThread(RepQuoteEnvironment env) {
+ myEnv = env;
+ }
+
+ public void run() {
+ for (;;) {
+ /*
+ * Wait for one minute, polling once per second to see if
+ * application has finished. When application has finished,
+ * terminate this thread.
+ */
+ for (int i = 0; i < 60; i++) {
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException ie) {}
+ if (myEnv.getAppFinished())
+ return;
+ }
+
+ /* Perform a checkpoint. */
+ try {
+ myEnv.checkpoint(null);
+ } catch (DatabaseException de) {
+ System.err.println("Could not perform checkpoint.");
+ }
+ }
+ }
+}
+
+/*
+ * This is a simple log archive thread. Once per minute, it removes all but
+ * the most recent 3 logs that are safe to remove according to a call to
+ * DBENV->log_archive().
+ *
+ * Log cleanup is needed to conserve disk space, but aggressive log cleanup
+ * can cause more frequent client initializations if a client lags too far
+ * behind the current master. This can happen in the event of a slow client,
+ * a network partition, or a new master that has not kept as many logs as the
+ * previous master.
+ *
+ * The approach in this routine balances the need to mitigate against a
+ * lagging client by keeping a few more of the most recent unneeded logs
+ * with the need to conserve disk space by regularly cleaning up log files.
+ * Use of automatic log removal (DBENV->log_set_config() DB_LOG_AUTO_REMOVE
+ * flag) is not recommended for replication due to the risk of frequent
+ * client initializations.
+ */
+class LogArchiveThread extends Thread {
+ private RepQuoteEnvironment myEnv = null;
+ private EnvironmentConfig myEnvConfig = null;
+
+ public LogArchiveThread(RepQuoteEnvironment env,
+ EnvironmentConfig envConfig) {
+ myEnv = env;
+ myEnvConfig = envConfig;
+ }
+
+ public void run() {
+ java.io.File[] logFileList;
+ int logs_to_keep = 3;
+ int minlog;
+
+ for (;;) {
+ /*
+ * Wait for one minute, polling once per second to see if
+ * application has finished. When application has finished,
+ * terminate this thread.
+ */
+ for (int i = 0; i < 60; i++) {
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException ie) {}
+ if (myEnv.getAppFinished())
+ return;
+ }
+
+ try {
+ /* Get the list of unneeded log files. */
+ logFileList = myEnv.getArchiveLogFiles(false);
+ /*
+ * Remove all but the logs_to_keep most recent unneeded
+ * log files.
+ */
+ minlog = logFileList.length - logs_to_keep;
+ for (int i = 0; i < minlog; i++) {
+ logFileList[i].delete();
+ }
+ } catch (DatabaseException de) {
+ System.err.println("Problem deleting log archive files.");
+ }
+ }
+ }
+}
diff --git a/examples_java/src/db/repquote/RepRemoteHost.java b/examples_java/src/db/repquote/RepRemoteHost.java
new file mode 100644
index 0000000..06623ba
--- /dev/null
+++ b/examples_java/src/db/repquote/RepRemoteHost.java
@@ -0,0 +1,29 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 1997-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package db.repquote;
+
+import com.sleepycat.db.ReplicationHostAddress;
+
+public class RepRemoteHost{
+ private ReplicationHostAddress addr;
+ private boolean isPeer;
+
+ public RepRemoteHost(ReplicationHostAddress remoteAddr, boolean hostIsPeer){
+ addr = remoteAddr;
+ isPeer = hostIsPeer;
+ }
+
+ public ReplicationHostAddress getAddress(){
+ return addr;
+ }
+
+ public boolean isPeer(){
+ return isPeer;
+ }
+}
diff --git a/examples_java/src/db/repquote_gsg/RepConfig.java b/examples_java/src/db/repquote_gsg/RepConfig.java
new file mode 100644
index 0000000..1dbf24c
--- /dev/null
+++ b/examples_java/src/db/repquote_gsg/RepConfig.java
@@ -0,0 +1,105 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2001-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package db.repquote_gsg;
+
+import java.util.Vector;
+
+import com.sleepycat.db.ReplicationHostAddress;
+import com.sleepycat.db.ReplicationManagerStartPolicy;
+
+public class RepConfig
+{
+ // Constant values used in the RepQuote application.
+ public static final String progname = "RepQuoteExampleGSG";
+ public static final int CACHESIZE = 10 * 1024 * 1024;
+ public static final int SLEEPTIME = 5000;
+
+ // Member variables containing configuration information.
+ // String specifying the home directory for rep files.
+ public String home;
+ // Stores an optional set of "other" hosts.
+ public Vector<ReplicationHostAddress> otherHosts;
+ // Priority within the replication group.
+ public int priority;
+ public ReplicationManagerStartPolicy startPolicy;
+ // The host address to listen to.
+ public ReplicationHostAddress thisHost;
+ // Optional parameter specifying the # of sites in the
+ // replication group.
+ public int totalSites;
+
+ // Member variables used internally.
+ private int currOtherHost;
+ private boolean gotListenAddress;
+
+ public RepConfig()
+ {
+ startPolicy = ReplicationManagerStartPolicy.REP_ELECTION;
+ home = "";
+ gotListenAddress = false;
+ totalSites = 0;
+ priority = 100;
+ currOtherHost = 0;
+ thisHost = new ReplicationHostAddress();
+ otherHosts = new Vector<ReplicationHostAddress>();
+ }
+
+ public java.io.File getHome()
+ {
+ return new java.io.File(home);
+ }
+
+ public void setThisHost(String host, int port)
+ {
+ gotListenAddress = true;
+ thisHost.port = port;
+ thisHost.host = host;
+ }
+
+ public ReplicationHostAddress getThisHost()
+ {
+ if (!gotListenAddress)
+ System.err.println("Warning: no host specified, returning default.");
+ return thisHost;
+ }
+
+ public boolean gotListenAddress() {
+ return gotListenAddress;
+ }
+
+ public void addOtherHost(String host, int port)
+ {
+ ReplicationHostAddress newInfo = new ReplicationHostAddress(host, port);
+ otherHosts.add(newInfo);
+ }
+
+ public ReplicationHostAddress getFirstOtherHost()
+ {
+ currOtherHost = 0;
+ if (otherHosts.size() == 0)
+ return null;
+ return (ReplicationHostAddress)otherHosts.get(currOtherHost);
+ }
+
+ public ReplicationHostAddress getNextOtherHost()
+ {
+ currOtherHost++;
+ if (currOtherHost >= otherHosts.size())
+ return null;
+ return (ReplicationHostAddress)otherHosts.get(currOtherHost);
+ }
+
+ public ReplicationHostAddress getOtherHost(int i)
+ {
+ if (i >= otherHosts.size())
+ return null;
+ return (ReplicationHostAddress)otherHosts.get(i);
+ }
+}
+
diff --git a/examples_java/src/db/repquote_gsg/RepQuoteEnvironment.java b/examples_java/src/db/repquote_gsg/RepQuoteEnvironment.java
new file mode 100644
index 0000000..2a830fb
--- /dev/null
+++ b/examples_java/src/db/repquote_gsg/RepQuoteEnvironment.java
@@ -0,0 +1,40 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2001-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package db.repquote_gsg;
+
+import com.sleepycat.db.*;
+
+/*
+ * A simple wrapper class, that facilitates storing some
+ * custom information with an Environment object.
+ * The information is used by the Replication callback (handleEvent).
+ */
+public class RepQuoteEnvironment extends Environment
+{
+ private boolean isMaster;
+
+ public RepQuoteEnvironment(final java.io.File host,
+ EnvironmentConfig config)
+ throws DatabaseException, java.io.FileNotFoundException
+ {
+ super(host, config);
+ isMaster = false;
+ }
+
+ boolean getIsMaster()
+ {
+ return isMaster;
+ }
+
+ public void setIsMaster(boolean isMaster)
+ {
+ this.isMaster = isMaster;
+ }
+}
+
diff --git a/examples_java/src/db/repquote_gsg/RepQuoteExampleGSG.java b/examples_java/src/db/repquote_gsg/RepQuoteExampleGSG.java
new file mode 100644
index 0000000..79740d7
--- /dev/null
+++ b/examples_java/src/db/repquote_gsg/RepQuoteExampleGSG.java
@@ -0,0 +1,383 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2001-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+// NOTE: This example is a simplified version of the RepQuoteExample.java
+// example that can be found in the db/examples_java/src/db/repquote directory.
+//
+// This example is intended only as an aid in learning Replication Manager
+// concepts. It is not complete in that many features are not exercised
+// in it, nor are many error conditions properly handled.
+
+package db.repquote_gsg;
+
+import java.io.FileNotFoundException;
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.lang.Thread;
+import java.lang.InterruptedException;
+
+import com.sleepycat.db.Cursor;
+import com.sleepycat.db.Database;
+import com.sleepycat.db.DatabaseConfig;
+import com.sleepycat.db.DatabaseEntry;
+import com.sleepycat.db.DatabaseException;
+import com.sleepycat.db.DeadlockException;
+import com.sleepycat.db.DatabaseType;
+import com.sleepycat.db.EnvironmentConfig;
+import com.sleepycat.db.EventHandler;
+import com.sleepycat.db.LockMode;
+import com.sleepycat.db.OperationStatus;
+import com.sleepycat.db.ReplicationHandleDeadException;
+import com.sleepycat.db.ReplicationHostAddress;
+import com.sleepycat.db.ReplicationManagerStartPolicy;
+import com.sleepycat.db.ReplicationManagerAckPolicy;
+import db.repquote_gsg.RepConfig;
+
+public class RepQuoteExampleGSG implements EventHandler
+{
+ private RepConfig repConfig;
+ private RepQuoteEnvironment dbenv;
+
+ public static void usage()
+ {
+ System.err.println("usage: " + RepConfig.progname);
+ System.err.println("-h home -l host:port [-r host:port]" +
+ "[-n nsites][-p priority]");
+
+ System.err.println("\t -h home directory (required)\n" +
+ "\t -l host:port (required; l stands for local)\n" +
+ "\t -r host:port (optional; r stands for remote; any " +
+ "number of these\n" +
+ "\t may be specified)\n" +
+ "\t -n nsites (optional; number of sites in replication " +
+ "group; defaults\n" +
+ "\t to 0 to try to dynamically compute nsites)\n" +
+ "\t -p priority (optional; defaults to 100)\n");
+
+ System.exit(1);
+ }
+
+ public static void main(String[] argv)
+ throws Exception
+ {
+ RepConfig config = new RepConfig();
+ String tmpHost;
+ int tmpPort = 0;
+ // Extract the command line parameters.
+ for (int i = 0; i < argv.length; i++)
+ {
+ if (argv[i].compareTo("-h") == 0) {
+ // home is a string arg.
+ i++;
+ config.home = argv[i];
+ } else if (argv[i].compareTo("-l") == 0) {
+ // "local" should be host:port.
+ i++;
+ String[] words = argv[i].split(":");
+ if (words.length != 2) {
+ System.err.println(
+ "Invalid host specification host:port needed.");
+ usage();
+ }
+ try {
+ tmpPort = Integer.parseInt(words[1]);
+ } catch (NumberFormatException nfe) {
+ System.err.println("Invalid host specification, " +
+ "could not parse port number.");
+ usage();
+ }
+ config.setThisHost(words[0], tmpPort);
+ } else if (argv[i].compareTo("-n") == 0) {
+ i++;
+ config.totalSites = Integer.parseInt(argv[i]);
+ } else if (argv[i].compareTo("-p") == 0) {
+ i++;
+ config.priority = Integer.parseInt(argv[i]);
+ } else if (argv[i].compareTo("-r") == 0) {
+ i++;
+ String[] words = argv[i].split(":");
+ if (words.length != 2) {
+ System.err.println(
+ "Invalid host specification host:port needed.");
+ usage();
+ }
+ try {
+ tmpPort = Integer.parseInt(words[1]);
+ } catch (NumberFormatException nfe) {
+ System.err.println("Invalid host specification, " +
+ "could not parse port number.");
+ usage();
+ }
+ config.addOtherHost(words[0], tmpPort);
+ } else {
+ System.err.println("Unrecognized option: " + argv[i]);
+ usage();
+ }
+
+ }
+
+ // Error check command line.
+ if ((!config.gotListenAddress()) || config.home.length() == 0)
+ usage();
+
+ RepQuoteExampleGSG runner = null;
+ try {
+ runner = new RepQuoteExampleGSG();
+ runner.init(config);
+
+ runner.doloop();
+ runner.terminate();
+ } catch (DatabaseException dbe) {
+ System.err.println("Caught an exception during " +
+ "initialization or processing: " + dbe.toString());
+ if (runner != null)
+ runner.terminate();
+ }
+ System.exit(0);
+ } // end main
+
+ public RepQuoteExampleGSG()
+ throws DatabaseException
+ {
+ repConfig = null;
+ dbenv = null;
+ }
+
+ public int init(RepConfig config)
+ throws DatabaseException
+ {
+ int ret = 0;
+ repConfig = config;
+ EnvironmentConfig envConfig = new EnvironmentConfig();
+ envConfig.setErrorStream(System.err);
+ envConfig.setErrorPrefix(RepConfig.progname);
+
+ envConfig.setReplicationManagerLocalSite(repConfig.getThisHost());
+ for (ReplicationHostAddress host = repConfig.getFirstOtherHost();
+ host != null; host = repConfig.getNextOtherHost())
+ envConfig.replicationManagerAddRemoteSite(host, false);
+
+ if (repConfig.totalSites > 0)
+ envConfig.setReplicationNumSites(repConfig.totalSites);
+ envConfig.setReplicationPriority(repConfig.priority);
+
+ envConfig.setReplicationManagerAckPolicy(
+ ReplicationManagerAckPolicy.ALL);
+ envConfig.setCacheSize(RepConfig.CACHESIZE);
+ envConfig.setTxnNoSync(true);
+
+ envConfig.setEventHandler(this);
+
+ envConfig.setAllowCreate(true);
+ envConfig.setRunRecovery(true);
+ envConfig.setThreaded(true);
+ envConfig.setInitializeReplication(true);
+ envConfig.setInitializeLocking(true);
+ envConfig.setInitializeLogging(true);
+ envConfig.setInitializeCache(true);
+ envConfig.setTransactional(true);
+ try {
+ dbenv = new RepQuoteEnvironment(repConfig.getHome(), envConfig);
+ } catch(FileNotFoundException e) {
+ System.err.println("FileNotFound exception: " + e.toString());
+ System.err.println(
+ "Ensure that the environment directory is pre-created.");
+ ret = 1;
+ }
+
+ // Start Replication Manager.
+ dbenv.replicationManagerStart(3, repConfig.startPolicy);
+ return ret;
+ }
+
+ // Provides the main data processing function for our application.
+ // This function provides a command line prompt to which the user
+ // can provide a ticker string and a stock price. Once a value is
+ // entered to the application, the application writes the value to
+ // the database and then displays the entire database.
+ public int doloop()
+ throws DatabaseException
+ {
+ Database db = null;
+
+ for (;;)
+ {
+ if (db == null) {
+ DatabaseConfig dbconf = new DatabaseConfig();
+ dbconf.setType(DatabaseType.BTREE);
+ if (dbenv.getIsMaster()) {
+ dbconf.setAllowCreate(true);
+ }
+ dbconf.setTransactional(true);
+
+ try {
+ db = dbenv.openDatabase
+ (null, RepConfig.progname, null, dbconf);
+ } catch (java.io.FileNotFoundException e) {
+ System.err.println("No stock database available yet.");
+ if (db != null) {
+ db.close(true);
+ db = null;
+ }
+ try {
+ Thread.sleep(RepConfig.SLEEPTIME);
+ } catch (InterruptedException ie) {}
+ continue;
+ }
+ }
+
+ BufferedReader stdin =
+ new BufferedReader(new InputStreamReader(System.in));
+
+ // Listen for input, and add it to the database.
+ System.out.print("QUOTESERVER");
+ if (!dbenv.getIsMaster())
+ System.out.print("(read-only)");
+ System.out.print("> ");
+ System.out.flush();
+ String nextline = null;
+ try {
+ nextline = stdin.readLine();
+ } catch (IOException ioe) {
+ System.err.println("Unable to get data from stdin");
+ break;
+ }
+ String[] words = nextline.split("\\s");
+
+ // A blank line causes the DB to be dumped to stdout.
+ if (words.length == 0 ||
+ (words.length == 1 && words[0].length() == 0)) {
+ try {
+ printStocks(db);
+ } catch (DeadlockException de) {
+ continue;
+ // Dead replication handles are cased by an election
+ // resulting in a previously committing read becoming
+ // invalid. Close the db handle and reopen.
+ } catch (ReplicationHandleDeadException rhde) {
+ db.close(true); // close no sync.
+ db = null;
+ continue;
+ } catch (DatabaseException e) {
+ System.err.println("Got db exception reading replication" +
+ "DB: " + e.toString());
+ break;
+ }
+ continue;
+ }
+
+ if (words.length == 1 &&
+ (words[0].compareToIgnoreCase("quit") == 0 ||
+ words[0].compareToIgnoreCase("exit") == 0)) {
+ break;
+ } else if (words.length != 2) {
+ System.err.println("Format: TICKER VALUE");
+ continue;
+ }
+
+ if (!dbenv.getIsMaster()) {
+ System.err.println("Can't update client.");
+ continue;
+ }
+
+ DatabaseEntry key = new DatabaseEntry(words[0].getBytes());
+ DatabaseEntry data = new DatabaseEntry(words[1].getBytes());
+
+ db.put(null, key, data);
+ }
+ if (db != null)
+ db.close(true);
+ return 0;
+ }
+
+ public void terminate()
+ throws DatabaseException
+ {
+ dbenv.close();
+ }
+
+ public void handleRepClientEvent()
+ {
+ dbenv.setIsMaster(false);
+ }
+
+ public void handleRepMasterEvent()
+ {
+ dbenv.setIsMaster(true);
+ }
+
+ public void handleRepNewMasterEvent(int envId)
+ {
+ // Ignored for now.
+ }
+
+ public void handleWriteFailedEvent(int errorCode)
+ {
+ System.err.println("Write to stable storage failed!" +
+ "Operating system error code:" + errorCode);
+ System.err.println("Continuing....");
+ }
+
+ public void handleRepStartupDoneEvent()
+ {
+ // Ignored for now.
+ }
+
+ public void handleRepPermFailedEvent()
+ {
+ // Ignored for now.
+ }
+
+ public void handleRepElectedEvent()
+ {
+ // Safely ignored for Replication Manager applications.
+ }
+
+ public void handlePanicEvent()
+ {
+ System.err.println("Panic encountered!");
+ System.err.println("Shutting down.");
+ System.err.println("You should restart, running recovery.");
+ try {
+ terminate();
+ } catch (DatabaseException dbe) {
+ System.err.println("Caught an exception during " +
+ "termination in handlePanicEvent: " + dbe.toString());
+ }
+ System.exit(-1);
+ }
+
+ // Display all the stock quote information in the database.
+ // Return type is void because error conditions are propagated
+ // via exceptions.
+ private void printStocks(Database db)
+ throws DeadlockException, DatabaseException
+ {
+ Cursor dbc = db.openCursor(null, null);
+
+ System.out.println("\tSymbol\tPrice");
+ System.out.println("\t======\t=====");
+
+ DatabaseEntry key = new DatabaseEntry();
+ DatabaseEntry data = new DatabaseEntry();
+ OperationStatus ret;
+ for (ret = dbc.getFirst(key, data, LockMode.DEFAULT);
+ ret == OperationStatus.SUCCESS;
+ ret = dbc.getNext(key, data, LockMode.DEFAULT)) {
+ String keystr = new String
+ (key.getData(), key.getOffset(), key.getSize());
+ String datastr = new String
+ (data.getData(), data.getOffset(), data.getSize());
+ System.out.println("\t"+keystr+"\t"+datastr);
+ }
+ dbc.close();
+ }
+} // end class
+
diff --git a/examples_java/src/db/repquote_gsg/SimpleConfig.java b/examples_java/src/db/repquote_gsg/SimpleConfig.java
new file mode 100644
index 0000000..7807289
--- /dev/null
+++ b/examples_java/src/db/repquote_gsg/SimpleConfig.java
@@ -0,0 +1,32 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2001-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package db.repquote_gsg;
+
+public class SimpleConfig
+{
+ // Constant values used in the RepQuote application.
+ public static final String progname = "SimpleTxn";
+ public static final int CACHESIZE = 10 * 1024 * 1024;
+
+ // Member variables containing configuration information.
+ public String home; // String specifying the home directory for
+ // rep files.
+
+ public SimpleConfig()
+ {
+ home = "";
+ }
+
+ public java.io.File getHome()
+ {
+ return new java.io.File(home);
+ }
+
+}
+
diff --git a/examples_java/src/db/repquote_gsg/SimpleTxn.java b/examples_java/src/db/repquote_gsg/SimpleTxn.java
new file mode 100644
index 0000000..5b95a3a
--- /dev/null
+++ b/examples_java/src/db/repquote_gsg/SimpleTxn.java
@@ -0,0 +1,229 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2001-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package db.repquote_gsg;
+
+import java.io.FileNotFoundException;
+// BufferedReader and InputStreamReader needed for our command line
+// prompt.
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+
+import com.sleepycat.db.Cursor;
+import com.sleepycat.db.Database;
+import com.sleepycat.db.DatabaseConfig;
+import com.sleepycat.db.DatabaseEntry;
+import com.sleepycat.db.DatabaseException;
+import com.sleepycat.db.DatabaseType;
+import com.sleepycat.db.Environment;
+import com.sleepycat.db.EnvironmentConfig;
+import com.sleepycat.db.LockMode;
+import com.sleepycat.db.OperationStatus;
+import db.repquote_gsg.SimpleConfig;
+
+public class SimpleTxn
+{
+ private SimpleConfig simpleConfig;
+ private Environment dbenv;
+
+ public SimpleTxn()
+ throws DatabaseException
+ {
+ simpleConfig = null;
+ dbenv = null;
+ }
+
+ public static void usage()
+ {
+ System.err.println("usage: " + SimpleConfig.progname + " -h home");
+ System.exit(1);
+ }
+
+ public static void main(String[] argv)
+ throws Exception
+ {
+ SimpleConfig config = new SimpleConfig();
+ // Extract the command line parameters.
+ for (int i = 0; i < argv.length; i++)
+ {
+ if (argv[i].compareTo("-h") == 0) {
+ // home - a string arg.
+ i++;
+ config.home = argv[i];
+ } else {
+ System.err.println("Unrecognized option: " + argv[i]);
+ usage();
+ }
+ }
+
+ // Error check command line.
+ if (config.home.length() == 0)
+ usage();
+
+ SimpleTxn runner = null;
+ try {
+ runner = new SimpleTxn();
+ runner.init(config);
+
+ runner.doloop();
+ runner.terminate();
+ } catch (DatabaseException dbe) {
+ System.err.println("Caught an exception during " +
+ "initialization or processing: " + dbe.toString());
+ if (runner != null)
+ runner.terminate();
+ }
+ System.exit(0);
+ } // end main
+
+ public int init(SimpleConfig config)
+ throws DatabaseException
+ {
+ int ret = 0;
+ simpleConfig = config;
+ EnvironmentConfig envConfig = new EnvironmentConfig();
+ envConfig.setErrorStream(System.err);
+ envConfig.setErrorPrefix(SimpleConfig.progname);
+
+ envConfig.setCacheSize(SimpleConfig.CACHESIZE);
+ envConfig.setTxnNoSync(true);
+
+ envConfig.setAllowCreate(true);
+ envConfig.setRunRecovery(true);
+ envConfig.setInitializeLocking(true);
+ envConfig.setInitializeLogging(true);
+ envConfig.setInitializeCache(true);
+ envConfig.setTransactional(true);
+ try {
+ dbenv = new Environment(simpleConfig.getHome(), envConfig);
+ } catch(FileNotFoundException e) {
+ System.err.println("FileNotFound exception: " + e.toString());
+ System.err.println(
+ "Ensure that the environment directory is pre-created.");
+ ret = 1;
+ }
+
+ return ret;
+ }
+
+ // Provides the main data processing function for our application.
+ // This function provides a command line prompt to which the user
+ // can provide a ticker string and a stock price. Once a value is
+ // entered to the application, the application writes the value to
+ // the database and then displays the entire database.
+ public int doloop()
+ throws DatabaseException, UnsupportedEncodingException
+ {
+ Database db = null;
+
+ for (;;)
+ {
+ if (db == null) {
+ DatabaseConfig dbconf = new DatabaseConfig();
+ dbconf.setType(DatabaseType.BTREE);
+ dbconf.setAllowCreate(true);
+ dbconf.setTransactional(true);
+
+ try {
+ db = dbenv.openDatabase(null, // txn handle
+ SimpleConfig.progname, // db filename
+ null, // db name
+ dbconf);
+ } catch (FileNotFoundException fnfe) {
+ System.err.println("File not found exception" +
+ fnfe.toString());
+ // Get here only if the environment home directory
+ // somehow does not exist.
+ }
+ }
+
+ BufferedReader stdin =
+ new BufferedReader(new InputStreamReader(System.in));
+
+ // Listen for input, and add it to the database.
+ System.out.print("QUOTESERVER> ");
+ System.out.flush();
+ String nextline = null;
+ try {
+ nextline = stdin.readLine();
+ } catch (IOException ioe) {
+ System.err.println("Unable to get data from stdin");
+ break;
+ }
+ String[] words = nextline.split("\\s");
+
+ // A blank line causes the DB to be dumped to stdout.
+ if (words.length == 0 ||
+ (words.length == 1 && words[0].length() == 0)) {
+ try {
+ printStocks(db);
+ } catch (DatabaseException e) {
+ System.err.println("Got db exception reading " +
+ "DB: " + e.toString());
+ break;
+ }
+ continue;
+ }
+
+ if (words.length == 1 &&
+ (words[0].compareToIgnoreCase("quit") == 0 ||
+ words[0].compareToIgnoreCase("exit") == 0)) {
+ break;
+ } else if (words.length != 2) {
+ System.err.println("Format: TICKER VALUE");
+ continue;
+ }
+
+ DatabaseEntry key =
+ new DatabaseEntry(words[0].getBytes("UTF-8"));
+ DatabaseEntry data =
+ new DatabaseEntry(words[1].getBytes("UTF-8"));
+
+ db.put(null, key, data);
+ }
+ if (db != null)
+ db.close(true);
+ return 0;
+ }
+
+ public void terminate()
+ throws DatabaseException
+ {
+ dbenv.close();
+ }
+
+ // Display all the stock quote information in the database.
+ // Return type is void because error conditions are propagated
+ // via exceptions.
+ private void printStocks(Database db)
+ throws DatabaseException
+ {
+ Cursor dbc = db.openCursor(null, null);
+
+ System.out.println("\tSymbol\tPrice");
+ System.out.println("\t======\t=====");
+
+ DatabaseEntry key = new DatabaseEntry();
+ DatabaseEntry data = new DatabaseEntry();
+ OperationStatus ret;
+ for (ret = dbc.getFirst(key, data, LockMode.DEFAULT);
+ ret == OperationStatus.SUCCESS;
+ ret = dbc.getNext(key, data, LockMode.DEFAULT)) {
+ String keystr = new String
+ (key.getData(), key.getOffset(), key.getSize());
+ String datastr = new String
+ (data.getData(), data.getOffset(), data.getSize());
+ System.out.println("\t"+keystr+"\t"+datastr);
+
+ }
+ dbc.close();
+ }
+} // end class
+
diff --git a/examples_java/src/db/txn/DBWriter.java b/examples_java/src/db/txn/DBWriter.java
new file mode 100644
index 0000000..bb60fa4
--- /dev/null
+++ b/examples_java/src/db/txn/DBWriter.java
@@ -0,0 +1,213 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2005-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package db.txn;
+
+import com.sleepycat.bind.EntryBinding;
+import com.sleepycat.bind.serial.StoredClassCatalog;
+import com.sleepycat.bind.serial.SerialBinding;
+import com.sleepycat.bind.tuple.StringBinding;
+
+import com.sleepycat.db.Cursor;
+import com.sleepycat.db.CursorConfig;
+import com.sleepycat.db.Database;
+import com.sleepycat.db.DatabaseEntry;
+import com.sleepycat.db.DatabaseException;
+import com.sleepycat.db.DeadlockException;
+import com.sleepycat.db.Environment;
+import com.sleepycat.db.LockMode;
+import com.sleepycat.db.OperationStatus;
+import com.sleepycat.db.Transaction;
+
+import java.io.UnsupportedEncodingException;
+import java.util.Random;
+
+public class DBWriter extends Thread
+{
+ private Database myDb = null;
+ private Environment myEnv = null;
+ private EntryBinding dataBinding = null;
+ private Random generator = new Random();
+ private boolean passTxn = false;
+
+
+ private static final int MAX_RETRY = 20;
+
+ private static String[] keys = {"key 1", "key 2", "key 3",
+ "key 4", "key 5", "key 6",
+ "key 7", "key 8", "key 9",
+ "key 10"};
+
+
+ // Constructor. Get our DB handles from here
+ // This consturctor allows us to indicate whether the
+ // txn handle should be handed to countRecords()
+ DBWriter(Environment env, Database db, StoredClassCatalog scc,
+ boolean passtxn)
+
+ throws DatabaseException {
+ myDb = db;
+ myEnv = env;
+ dataBinding = new SerialBinding(scc, PayloadData.class);
+
+ passTxn = passtxn;
+ }
+
+ // Constructor. Get our DB handles from here
+ DBWriter(Environment env, Database db, StoredClassCatalog scc)
+
+ throws DatabaseException {
+ myDb = db;
+ myEnv = env;
+ dataBinding = new SerialBinding(scc, PayloadData.class);
+ }
+
+ // Thread method that writes a series of records
+ // to the database using transaction protection.
+ // Deadlock handling is demonstrated here.
+ public void run () {
+ Transaction txn = null;
+
+ // Perform 50 transactions
+ for (int i=0; i<50; i++) {
+
+ boolean retry = true;
+ int retry_count = 0;
+ // while loop is used for deadlock retries
+ while (retry) {
+ // try block used for deadlock detection and
+ // general db exception handling
+ try {
+
+ // Get a transaction
+ txn = myEnv.beginTransaction(null, null);
+
+ // Write 10 records to the db
+ // for each transaction
+ for (int j = 0; j < 10; j++) {
+ // Get the key
+ DatabaseEntry key = new DatabaseEntry();
+ StringBinding.stringToEntry(keys[j], key);
+
+ // Get the data
+ PayloadData pd = new PayloadData(i+j, getName(),
+ generator.nextDouble());
+ DatabaseEntry data = new DatabaseEntry();
+ dataBinding.objectToEntry(pd, data);
+
+ // Do the put
+ myDb.put(txn, key, data);
+ }
+
+ // commit
+ System.out.println(getName() + " : committing txn : " + i);
+
+ // This code block allows us to decide if txn handle is
+ // passed to countRecords()
+ //
+ // TxnGuideInMemory requires a txn handle be handed to
+ // countRecords(). The code self deadlocks if you don't.
+ // TxnGuide has no such requirement because it supports
+ // uncommitted reads.
+ Transaction txnHandle = null;
+ if (passTxn) { txnHandle = txn; }
+
+ System.out.println(getName() + " : Found " +
+ countRecords(txnHandle) + " records in the database.");
+ try {
+ txn.commit();
+ txn = null;
+ } catch (DatabaseException e) {
+ System.err.println("Error on txn commit: " +
+ e.toString());
+ }
+ retry = false;
+
+ } catch (DeadlockException de) {
+ System.out.println("################# " + getName() +
+ " : caught deadlock");
+ // retry if necessary
+ if (retry_count < MAX_RETRY) {
+ System.err.println(getName() +
+ " : Retrying operation.");
+ retry = true;
+ retry_count++;
+ } else {
+ System.err.println(getName() +
+ " : out of retries. Giving up.");
+ retry = false;
+ }
+ } catch (DatabaseException e) {
+ // abort and don't retry
+ retry = false;
+ System.err.println(getName() +
+ " : caught exception: " + e.toString());
+ System.err.println(getName() +
+ " : errno: " + e.getErrno());
+ e.printStackTrace();
+ } finally {
+ if (txn != null) {
+ try {
+ txn.abort();
+ } catch (Exception e) {
+ System.err.println("Error aborting transaction: " +
+ e.toString());
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // This simply counts the number of records contained in the
+ // database and returns the result. You can use this method
+ // in three ways:
+ //
+ // First call it with an active txn handle.
+ //
+ // Secondly, configure the cursor for dirty reads
+ //
+ // Third, call countRecords AFTER the writer has committed
+ // its transaction.
+ //
+ // If you do none of these things, the writer thread will
+ // self-deadlock.
+ //
+ // Note that this method exists only for illustrative purposes.
+ // A more straight-forward way to count the number of records in
+ // a database is to use the Database.getStats() method.
+ private int countRecords(Transaction txn) throws DatabaseException {
+ DatabaseEntry key = new DatabaseEntry();
+ DatabaseEntry data = new DatabaseEntry();
+ int count = 0;
+ Cursor cursor = null;
+
+ try {
+ // Get the cursor
+ CursorConfig cc = new CursorConfig();
+ // setReadUncommitted is ignored if the database was not
+ // opened for uncommitted read support. TxnGuide opens
+ // its database in this way, TxnGuideInMemory does not.
+ cc.setReadUncommitted(true);
+ cursor = myDb.openCursor(txn, cc);
+ while (cursor.getNext(key, data, LockMode.DEFAULT) ==
+ OperationStatus.SUCCESS) {
+
+ count++;
+ }
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
+ }
+
+ return count;
+
+ }
+}
diff --git a/examples_java/src/db/txn/PayloadData.java b/examples_java/src/db/txn/PayloadData.java
new file mode 100644
index 0000000..9151dd1
--- /dev/null
+++ b/examples_java/src/db/txn/PayloadData.java
@@ -0,0 +1,27 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2005-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+package db.txn;
+
+import java.io.Serializable;
+
+public class PayloadData implements Serializable {
+ private int oID;
+ private String threadName;
+ private double doubleData;
+
+ PayloadData(int id, String name, double data) {
+ oID = id;
+ threadName = name;
+ doubleData = data;
+ }
+
+ public double getDoubleData() { return doubleData; }
+ public int getID() { return oID; }
+ public String getThreadName() { return threadName; }
+}
diff --git a/examples_java/src/db/txn/TxnGuide.java b/examples_java/src/db/txn/TxnGuide.java
new file mode 100644
index 0000000..73d172f
--- /dev/null
+++ b/examples_java/src/db/txn/TxnGuide.java
@@ -0,0 +1,181 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2005-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+// File TxnGuide.java
+
+package db.txn;
+
+import com.sleepycat.bind.serial.StoredClassCatalog;
+
+import com.sleepycat.db.Database;
+import com.sleepycat.db.DatabaseConfig;
+import com.sleepycat.db.DatabaseException;
+import com.sleepycat.db.DatabaseType;
+import com.sleepycat.db.LockDetectMode;
+
+import com.sleepycat.db.Environment;
+import com.sleepycat.db.EnvironmentConfig;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+
+public class TxnGuide {
+
+ private static String myEnvPath = "./";
+ private static String dbName = "mydb.db";
+ private static String cdbName = "myclassdb.db";
+
+ // DB handles
+ private static Database myDb = null;
+ private static Database myClassDb = null;
+ private static Environment myEnv = null;
+
+ private static final int NUMTHREADS = 5;
+
+ private static void usage() {
+ System.out.println("TxnGuide [-h <env directory>]");
+ System.exit(-1);
+ }
+
+ public static void main(String args[]) {
+ try {
+ // Parse the arguments list
+ parseArgs(args);
+ // Open the environment and databases
+ openEnv();
+ // Get our class catalog (used to serialize objects)
+ StoredClassCatalog classCatalog =
+ new StoredClassCatalog(myClassDb);
+
+ // Start the threads
+ DBWriter[] threadArray;
+ threadArray = new DBWriter[NUMTHREADS];
+ for (int i = 0; i < NUMTHREADS; i++) {
+ threadArray[i] = new DBWriter(myEnv, myDb, classCatalog);
+ threadArray[i].start();
+ }
+
+ for (int i = 0; i < NUMTHREADS; i++) {
+ threadArray[i].join();
+ }
+ } catch (Exception e) {
+ System.err.println("TxnGuide: " + e.toString());
+ e.printStackTrace();
+ } finally {
+ closeEnv();
+ }
+ System.out.println("All done.");
+ }
+
+
+ private static void openEnv() throws DatabaseException {
+ System.out.println("opening env");
+
+ // Set up the environment.
+ EnvironmentConfig myEnvConfig = new EnvironmentConfig();
+ myEnvConfig.setAllowCreate(true);
+ myEnvConfig.setInitializeCache(true);
+ myEnvConfig.setInitializeLocking(true);
+ myEnvConfig.setInitializeLogging(true);
+ myEnvConfig.setRunRecovery(true);
+ myEnvConfig.setTransactional(true);
+ // EnvironmentConfig.setThreaded(true) is the default behavior
+ // in Java, so we do not have to do anything to cause the
+ // environment handle to be free-threaded.
+
+ // Indicate that we want db to internally perform deadlock
+ // detection. Also indicate that the transaction that has
+ // performed the least amount of write activity to
+ // receive the deadlock notification, if any.
+ myEnvConfig.setLockDetectMode(LockDetectMode.MINWRITE);
+
+ // Set up the database
+ DatabaseConfig myDbConfig = new DatabaseConfig();
+ myDbConfig.setType(DatabaseType.BTREE);
+ myDbConfig.setAllowCreate(true);
+ myDbConfig.setTransactional(true);
+ myDbConfig.setSortedDuplicates(true);
+ myDbConfig.setReadUncommitted(true);
+ // no DatabaseConfig.setThreaded() method available.
+ // db handles in java are free-threaded so long as the
+ // env is also free-threaded.
+
+ try {
+ // Open the environment
+ myEnv = new Environment(new File(myEnvPath), // Env home
+ myEnvConfig);
+
+ // Open the database. Do not provide a txn handle. This open
+ // is autocommitted because DatabaseConfig.setTransactional()
+ // is true.
+ myDb = myEnv.openDatabase(null, // txn handle
+ dbName, // Database file name
+ null, // Database name
+ myDbConfig);
+
+ // Used by the bind API for serializing objects
+ // Class database must not support duplicates
+ myDbConfig.setSortedDuplicates(false);
+ myClassDb = myEnv.openDatabase(null, // txn handle
+ cdbName, // Database file name
+ null, // Database name,
+ myDbConfig);
+ } catch (FileNotFoundException fnfe) {
+ System.err.println("openEnv: " + fnfe.toString());
+ System.exit(-1);
+ }
+ }
+
+ private static void closeEnv() {
+ System.out.println("Closing env and databases");
+ if (myDb != null ) {
+ try {
+ myDb.close();
+ } catch (DatabaseException e) {
+ System.err.println("closeEnv: myDb: " +
+ e.toString());
+ e.printStackTrace();
+ }
+ }
+
+ if (myClassDb != null ) {
+ try {
+ myClassDb.close();
+ } catch (DatabaseException e) {
+ System.err.println("closeEnv: myClassDb: " +
+ e.toString());
+ e.printStackTrace();
+ }
+ }
+
+ if (myEnv != null ) {
+ try {
+ myEnv.close();
+ } catch (DatabaseException e) {
+ System.err.println("closeEnv: " + e.toString());
+ e.printStackTrace();
+ }
+ }
+ }
+
+ private TxnGuide() {}
+
+ private static void parseArgs(String args[]) {
+ for(int i = 0; i < args.length; ++i) {
+ if (args[i].startsWith("-")) {
+ switch(args[i].charAt(1)) {
+ case 'h':
+ myEnvPath = new String(args[++i]);
+ break;
+ default:
+ usage();
+ }
+ }
+ }
+ }
+}
diff --git a/examples_java/src/db/txn/TxnGuideInMemory.java b/examples_java/src/db/txn/TxnGuideInMemory.java
new file mode 100644
index 0000000..1955a8f
--- /dev/null
+++ b/examples_java/src/db/txn/TxnGuideInMemory.java
@@ -0,0 +1,172 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2005-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+// File TxnGuideInMemory.java
+
+package db.txn;
+
+import com.sleepycat.bind.serial.StoredClassCatalog;
+
+import com.sleepycat.db.Database;
+import com.sleepycat.db.DatabaseConfig;
+import com.sleepycat.db.DatabaseException;
+import com.sleepycat.db.DatabaseType;
+import com.sleepycat.db.LockDetectMode;
+
+import com.sleepycat.db.Environment;
+import com.sleepycat.db.EnvironmentConfig;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+
+public class TxnGuideInMemory {
+
+ // DB handles
+ private static Database myDb = null;
+ private static Database myClassDb = null;
+ private static Environment myEnv = null;
+
+ private static int NUMTHREADS = 5;
+
+ public static void main(String args[]) {
+ try {
+ // Open the environment and databases
+ openEnv();
+
+ // Get our class catalog (used to serialize objects)
+ StoredClassCatalog classCatalog =
+ new StoredClassCatalog(myClassDb);
+
+ // Start the threads
+ DBWriter[] threadArray;
+ threadArray = new DBWriter[NUMTHREADS];
+ for (int i = 0; i < NUMTHREADS; i++) {
+ threadArray[i] = new DBWriter(myEnv, myDb, classCatalog, true);
+ threadArray[i].start();
+ }
+
+ System.out.println("Threads started.\n");
+
+ for (int i = 0; i < NUMTHREADS; i++) {
+ threadArray[i].join();
+ }
+ } catch (Exception e) {
+ System.err.println("TxnGuideInMemory: " + e.toString());
+ e.printStackTrace();
+ } finally {
+ closeEnv();
+ }
+ System.out.println("All done.");
+ }
+
+ private static void openEnv() throws DatabaseException {
+ System.out.println("opening env");
+
+ // Set up the environment.
+ EnvironmentConfig myEnvConfig = new EnvironmentConfig();
+
+ // Region files are not backed by the filesystem, they are
+ // backed by heap memory.
+ myEnvConfig.setPrivate(true);
+ myEnvConfig.setAllowCreate(true);
+ myEnvConfig.setInitializeCache(true);
+ myEnvConfig.setInitializeLocking(true);
+ myEnvConfig.setInitializeLogging(true);
+ myEnvConfig.setThreaded(true);
+
+ myEnvConfig.setTransactional(true);
+ // EnvironmentConfig.setThreaded(true) is the default behavior
+ // in Java, so we do not have to do anything to cause the
+ // environment handle to be free-threaded.
+
+ // Indicate that we want db to internally perform deadlock
+ // detection. Also indicate that the transaction that has
+ // performed the least amount of write activity to
+ // receive the deadlock notification, if any.
+ myEnvConfig.setLockDetectMode(LockDetectMode.MINWRITE);
+
+ // Specify in-memory logging
+ myEnvConfig.setLogInMemory(true);
+ // Specify the size of the in-memory log buffer
+ // Must be large enough to handle the log data created by
+ // the largest transaction.
+ myEnvConfig.setLogBufferSize(10 * 1024 * 1024);
+ // Specify the size of the in-memory cache
+ // Set it large enough so that it won't page.
+ myEnvConfig.setCacheSize(10 * 1024 * 1024);
+
+ // Set up the database
+ DatabaseConfig myDbConfig = new DatabaseConfig();
+ myDbConfig.setType(DatabaseType.BTREE);
+ myDbConfig.setAllowCreate(true);
+ myDbConfig.setTransactional(true);
+ myDbConfig.setSortedDuplicates(true);
+ // no DatabaseConfig.setThreaded() method available.
+ // db handles in java are free-threaded so long as the
+ // env is also free-threaded.
+
+ try {
+ // Open the environment
+ myEnv = new Environment(null, // Env home
+ myEnvConfig);
+
+ // Open the database. Do not provide a txn handle. This open
+ // is autocommitted because DatabaseConfig.setTransactional()
+ // is true.
+ myDb = myEnv.openDatabase(null, // txn handle
+ null, // Database file name
+ null, // Database name
+ myDbConfig);
+
+ // Used by the bind API for serializing objects
+ // Class database must not support duplicates
+ myDbConfig.setSortedDuplicates(false);
+ myClassDb = myEnv.openDatabase(null, // txn handle
+ null, // Database file name
+ null, // Database name,
+ myDbConfig);
+ } catch (FileNotFoundException fnfe) {
+ System.err.println("openEnv: " + fnfe.toString());
+ System.exit(-1);
+ }
+ }
+
+ private static void closeEnv() {
+ System.out.println("Closing env");
+ if (myDb != null ) {
+ try {
+ myDb.close();
+ } catch (DatabaseException e) {
+ System.err.println("closeEnv: myDb: " +
+ e.toString());
+ e.printStackTrace();
+ }
+ }
+
+ if (myClassDb != null ) {
+ try {
+ myClassDb.close();
+ } catch (DatabaseException e) {
+ System.err.println("closeEnv: myClassDb: " +
+ e.toString());
+ e.printStackTrace();
+ }
+ }
+
+ if (myEnv != null ) {
+ try {
+ myEnv.close();
+ } catch (DatabaseException e) {
+ System.err.println("closeEnv: " + e.toString());
+ e.printStackTrace();
+ }
+ }
+ }
+
+ private TxnGuideInMemory() {}
+}