diff options
Diffstat (limited to 'examples_java/src/db')
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() {} +} |