• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src/router/db-4.8.30/examples_csharp/ex_txn/
1/*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 2009 Oracle.  All rights reserved.
5 *
6 */
7using System;
8using System.Collections.Generic;
9using System.IO;
10using System.Runtime.Serialization.Formatters.Binary;
11using System.Text;
12using System.Threading;
13
14using BerkeleyDB;
15
16namespace ex_txn {
17        public class ex_txn {
18		private DatabaseEnvironment env;
19		private Database db;
20		private Random generator = new Random();
21		private bool inMem;
22		private string dbName, home;
23		private const int NUMTHREADS = 5;
24
25		public static void Main(string[] args) {
26			/*
27			 * ex_txn is meant to be run from build_windows\AnyCPU,
28			 * in either the Debug or Release directory. The
29			 * required core libraries, however, are in either
30			 * build_windows\Win32 or build_windows\x64, depending
31			 * upon the platform.  That location needs to be added
32			 * to the PATH environment variable for the P/Invoke
33			 * calls to work.
34			 */
35			try {
36				String pwd = Environment.CurrentDirectory;
37				pwd = Path.Combine(pwd, "..");
38				pwd = Path.Combine(pwd, "..");
39				pwd = Path.Combine(pwd, "..");
40				pwd = Path.Combine(pwd, "build_windows");
41				if (IntPtr.Size == 4)
42					pwd = Path.Combine(pwd, "Win32");
43				else
44					pwd = Path.Combine(pwd, "x64");
45#if DEBUG
46				pwd = Path.Combine(pwd, "Debug");
47#else
48				pwd = Path.Combine(pwd, "Release");
49#endif
50				pwd += ";" + Environment.GetEnvironmentVariable("PATH");
51				Environment.SetEnvironmentVariable("PATH", pwd);
52			} catch (Exception e) {
53				Console.WriteLine(
54				    "Unable to set the PATH environment variable.");
55				Console.WriteLine(e.Message);
56				return;
57			}
58
59			ex_txn obj = new ex_txn();
60			obj.RunExample(args);
61		}
62
63		private void RunExample(string[] args) {
64			dbName = "ex_txn.db";
65			home = "TESTDIR";
66
67			if (!ParseArgs(args)) {
68				Usage();
69				return;
70			}
71
72			try {
73				Open();
74
75				// Start the threads.
76				Thread[] threadArray = new Thread[NUMTHREADS];
77				for (int i = 0; i < NUMTHREADS; i++) {
78					threadArray[i] = new Thread(
79                                            new ThreadStart(WriteData));
80					threadArray[i].Name = "Thread " + i;
81					threadArray[i].Start();
82				}
83
84				for (int i = 0; i < NUMTHREADS; i++) {
85					threadArray[i].Join();
86					Console.WriteLine("Thread " + i + " finished.");
87				}
88
89			} catch (DatabaseException e) {
90				Console.WriteLine("Caught exception: {0}", e.Message);
91				Console.WriteLine(e.StackTrace);
92			} finally {
93				Close();
94			}
95		}
96
97		private void Open() {
98			Console.WriteLine("Opening environment and database");
99
100			// Set up the environment.
101			DatabaseEnvironmentConfig envCfg = new DatabaseEnvironmentConfig();
102			envCfg.Create = true;
103			envCfg.UseMPool = true;
104			envCfg.UseLocking = true;
105			envCfg.UseLogging = true;
106			envCfg.UseTxns = true;
107
108			// Allow multiple threads visit to the environment handle.
109			envCfg.FreeThreaded = true;
110
111			if (inMem)
112				envCfg.Private = true;
113			else
114				envCfg.RunRecovery = true;
115
116			/*
117			 * Indicate that we want db to internally perform
118			 * deadlock detection, aborting the transaction that
119			 * has performed the least amount of WriteData activity
120			 * in the event of a deadlock.
121			 */
122			envCfg.LockSystemCfg = new LockingConfig();
123			envCfg.LockSystemCfg.DeadlockResolution =
124			    DeadlockPolicy.MIN_WRITE;
125
126			if (inMem) {
127				// Specify in-memory logging.
128				envCfg.LogSystemCfg = new LogConfig();
129				envCfg.LogSystemCfg.InMemory = true;
130
131				/*
132				 * Specify the size of the in-memory log buffer
133				 * Must be large enough to handle the log data
134				 * created by the largest transaction.
135				 */
136				envCfg.LogSystemCfg.BufferSize = 10 * 1024 * 1024;
137
138				/*
139				 * Specify the size of the in-memory cache,
140				 * large enough to avoid paging to disk.
141				 */
142				envCfg.MPoolSystemCfg = new MPoolConfig();
143				envCfg.MPoolSystemCfg.CacheSize =
144				    new CacheInfo(0, 10 * 1024 * 1024, 1);
145			}
146
147			// Set up the database.
148			BTreeDatabaseConfig dbCfg = new BTreeDatabaseConfig();
149			dbCfg.AutoCommit = true;
150			dbCfg.Creation = CreatePolicy.IF_NEEDED;
151			dbCfg.Duplicates = DuplicatesPolicy.SORTED;
152			dbCfg.FreeThreaded = true;
153			dbCfg.ReadUncommitted = true;
154
155			/*
156                         * Open the environment. Any errors will be caught
157                         * by the caller.
158                         */
159			env = DatabaseEnvironment.Open(home, envCfg);
160
161			/*
162			 * Open the database. Do not provide a txn handle. This
163			 * Open is autocommitted because BTreeDatabaseConfig.AutoCommit
164			 * is true.
165			 */
166			dbCfg.Env = env;
167			db = BTreeDatabase.Open(dbName, dbCfg);
168
169		}
170
171		private void Close() {
172			Console.WriteLine("Closing environment and database");
173			if (db != null) {
174				try {
175					db.Close();
176				} catch (DatabaseException e) {
177					Console.WriteLine("Error closing db: " + e.ToString());
178					Console.WriteLine(e.StackTrace);
179				}
180			}
181
182			if (env != null) {
183				try {
184					env.Close();
185				} catch (DatabaseException e) {
186					Console.WriteLine("Error closing env: " + e.ToString());
187					Console.WriteLine(e.StackTrace);
188				}
189			}
190		}
191
192		/*
193		 * This simply counts the number of records contained in the
194		 * database and returns the result. You can use this method
195		 * in three ways:
196		 *
197		 * First call it with an active txn handle.
198		 * Secondly, configure the cursor for dirty reads
199		 * Third, call countRecords AFTER the writer has committed
200		 * its transaction.
201		 *
202		 * If you do none of these things, the writer thread will
203		 * self-deadlock.
204		 *
205		 * Note that this method exists only for illustrative purposes.
206		 * A more straight-forward way to count the number of records in
207		 * a database is to use the Database.getStats() method.
208		 */
209		private int CountRecords(Transaction txn) {
210			int count = 0;
211			Cursor cursor = null;
212
213			try {
214				// Get the cursor.
215				CursorConfig cc = new CursorConfig();
216
217				/*
218				 * Isolation degree one is ignored if the
219				 * database was not opened for uncommitted
220				 * read support. TxnGuide opens its database
221				 * in this way and TxnGuideInMemory does not.
222				 */
223				cc.IsolationDegree = Isolation.DEGREE_ONE;
224				cursor = db.Cursor(cc, txn);
225				while (cursor.MoveNext())
226					count++;
227			} finally {
228				if (cursor != null)
229					cursor.Close();
230			}
231
232			return count;
233		}
234
235		private bool ParseArgs(string[] args) {
236			for (int i = 0; i < args.Length; i++) {
237				string s = args[i];
238				if (s[0] != '-') {
239					Console.Error.WriteLine(
240					    "Unrecognized option: " + args[i]);
241					return false;
242				}
243
244				switch (s[1]) {
245					case 'h':
246						home = args[++i];
247						break;
248					case 'm':
249						inMem = true;
250						break;
251					default:
252						Console.Error.WriteLine(
253						    "Unrecognized option: " + args[i]);
254						return false;
255				}
256			}
257			return true;
258		}
259
260		private void Usage() {
261			Console.WriteLine("ex_txn [-h <env directory>] [-m]");
262			Console.WriteLine("\t -h home (Set environment directory.)");
263			Console.WriteLine("\t -m (Run in memory, do not write to disk.)");
264		}
265
266		private void WriteData() {
267			/*
268			 * Write a series of records to the database using transaction
269			 * protection. Deadlock handling is demonstrated here.
270			 */
271			BinaryFormatter formatter = new BinaryFormatter();
272			MemoryStream ms = new MemoryStream();
273			Random generator = new Random();
274			Transaction txn = null;
275
276			string[] keys = {"key 1", "key 2", "key 3", "key 4",
277			    "key 5", "key 6", "key 7", "key 8", "key 9", "key 10"};
278
279			// Perform 20 transactions.
280			int iters = 0;
281			int retry_count = 0;
282			int maxRetry = 20;
283			while (iters < 50) {
284				try {
285					// Get a transaction.
286					txn = env.BeginTransaction();
287
288					// Write 10 records to the db for each transaction.
289					for (int j = 0; j < 10; j++) {
290						// Get the key.
291						DatabaseEntry key;
292						key = new DatabaseEntry(
293						    ASCIIEncoding.ASCII.GetBytes(keys[j]));
294
295						// Get the data.
296						PayloadData pd = new PayloadData(
297                                                    iters + j,
298						    Thread.CurrentThread.Name,
299						    generator.NextDouble());
300
301						formatter.Serialize(ms, pd);
302						Byte[] bytes = ms.GetBuffer();
303						DatabaseEntry data = new DatabaseEntry(bytes);
304
305						// Put key/data pair within the transaction.
306						db.Put(key, data, txn);
307					}
308
309					// Commit the transaction.
310					Console.WriteLine("{0} committing txn: {1}",
311					    Thread.CurrentThread.Name, iters);
312
313					int recCount = CountRecords(inMem ? txn : null);
314					Console.WriteLine("{0} found {1} records in the database.",
315					    Thread.CurrentThread.Name, recCount);
316
317					try {
318						txn.Commit();
319						txn = null;
320					} catch (DatabaseException e) {
321						Console.WriteLine(
322                                                    "Error on txn commit: " +
323                                                    e.ToString());
324					}
325
326					iters++;
327					retry_count = 0;
328				} catch (DeadlockException) {
329					Console.WriteLine(
330					    "##### {0} deadlocked.", Thread.CurrentThread.Name);
331
332					// Retry if necessary.
333					if (retry_count < maxRetry) {
334						Console.WriteLine("{0} retrying.",
335						    Thread.CurrentThread.Name);
336						retry_count++;
337					} else {
338						Console.WriteLine("{0} out of retries. Giving up.",
339						    Thread.CurrentThread.Name);
340						iters++;
341						retry_count = 0;
342					}
343				} catch (DatabaseException e) {
344					// Abort and don't retry.
345					iters++;
346					retry_count = 0;
347					Console.WriteLine(Thread.CurrentThread.Name +
348					    " : caught exception: " + e.ToString());
349					Console.WriteLine(Thread.CurrentThread.Name +
350					    " : errno: " + e.ErrorCode);
351					Console.WriteLine(e.StackTrace);
352				} finally {
353					if (txn != null) {
354						try {
355							txn.Abort();
356						} catch (DatabaseException e) {
357							Console.WriteLine("Error aborting transaction: " +
358							    e.ToString());
359							Console.WriteLine(e.StackTrace);
360						}
361					}
362				}
363			}
364		}
365	}
366}
367