| 
									
										
										
										
											2003-01-10 19:03:29 +00:00
										 |  |  | """TestCases for multi-threaded access to a DB.
 | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  | """
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-01-10 19:03:29 +00:00
										 |  |  | import os | 
					
						
							|  |  |  | import sys | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  | import time | 
					
						
							| 
									
										
										
										
											2003-01-10 19:03:29 +00:00
										 |  |  | import errno | 
					
						
							|  |  |  | import shutil | 
					
						
							|  |  |  | import tempfile | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  | from pprint import pprint | 
					
						
							|  |  |  | from whrandom import random | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-01-10 19:03:29 +00:00
										 |  |  | try: | 
					
						
							|  |  |  |     True, False | 
					
						
							|  |  |  | except NameError: | 
					
						
							|  |  |  |     True = 1 | 
					
						
							|  |  |  |     False = 0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | DASH = '-' | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  | try: | 
					
						
							|  |  |  |     from threading import Thread, currentThread | 
					
						
							| 
									
										
										
										
											2003-01-10 19:03:29 +00:00
										 |  |  |     have_threads = True | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  | except ImportError: | 
					
						
							| 
									
										
										
										
											2003-01-10 19:03:29 +00:00
										 |  |  |     have_threads = False | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | import unittest | 
					
						
							| 
									
										
										
										
											2002-12-30 20:53:52 +00:00
										 |  |  | from test_all import verbose | 
					
						
							| 
									
										
										
										
											2003-01-28 17:20:44 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | try: | 
					
						
							| 
									
										
										
										
											2003-09-21 00:08:14 +00:00
										 |  |  |     # For Pythons w/distutils pybsddb | 
					
						
							|  |  |  |     from bsddb3 import db, dbutils | 
					
						
							|  |  |  | except ImportError: | 
					
						
							| 
									
										
										
										
											2003-01-28 17:20:44 +00:00
										 |  |  |     # For Python 2.3 | 
					
						
							|  |  |  |     from bsddb import db, dbutils | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | #---------------------------------------------------------------------- | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class BaseThreadedTestCase(unittest.TestCase): | 
					
						
							|  |  |  |     dbtype       = db.DB_UNKNOWN  # must be set in derived class | 
					
						
							|  |  |  |     dbopenflags  = 0 | 
					
						
							|  |  |  |     dbsetflags   = 0 | 
					
						
							|  |  |  |     envflags     = 0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def setUp(self): | 
					
						
							| 
									
										
										
										
											2002-11-23 11:26:07 +00:00
										 |  |  |         if verbose: | 
					
						
							|  |  |  |             dbutils._deadlock_VerboseFile = sys.stdout | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  |         homeDir = os.path.join(os.path.dirname(sys.argv[0]), 'db_home') | 
					
						
							|  |  |  |         self.homeDir = homeDir | 
					
						
							| 
									
										
										
										
											2003-01-10 19:03:29 +00:00
										 |  |  |         try: | 
					
						
							|  |  |  |             os.mkdir(homeDir) | 
					
						
							|  |  |  |         except OSError, e: | 
					
						
							|  |  |  |             if e.errno <> errno.EEXIST: raise | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  |         self.env = db.DBEnv() | 
					
						
							|  |  |  |         self.setEnvOpts() | 
					
						
							|  |  |  |         self.env.open(homeDir, self.envflags | db.DB_CREATE) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.filename = self.__class__.__name__ + '.db' | 
					
						
							|  |  |  |         self.d = db.DB(self.env) | 
					
						
							|  |  |  |         if self.dbsetflags: | 
					
						
							|  |  |  |             self.d.set_flags(self.dbsetflags) | 
					
						
							|  |  |  |         self.d.open(self.filename, self.dbtype, self.dbopenflags|db.DB_CREATE) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def tearDown(self): | 
					
						
							|  |  |  |         self.d.close() | 
					
						
							|  |  |  |         self.env.close() | 
					
						
							| 
									
										
										
										
											2003-01-10 19:03:29 +00:00
										 |  |  |         shutil.rmtree(self.homeDir) | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def setEnvOpts(self): | 
					
						
							|  |  |  |         pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def makeData(self, key): | 
					
						
							| 
									
										
										
										
											2003-01-10 19:03:29 +00:00
										 |  |  |         return DASH.join([key] * 5) | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #---------------------------------------------------------------------- | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class ConcurrentDataStoreBase(BaseThreadedTestCase): | 
					
						
							|  |  |  |     dbopenflags = db.DB_THREAD | 
					
						
							|  |  |  |     envflags    = db.DB_THREAD | db.DB_INIT_CDB | db.DB_INIT_MPOOL | 
					
						
							|  |  |  |     readers     = 0 # derived class should set | 
					
						
							|  |  |  |     writers     = 0 | 
					
						
							|  |  |  |     records     = 1000 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test01_1WriterMultiReaders(self): | 
					
						
							|  |  |  |         if verbose: | 
					
						
							|  |  |  |             print '\n', '-=' * 30 | 
					
						
							| 
									
										
										
										
											2002-12-30 20:53:52 +00:00
										 |  |  |             print "Running %s.test01_1WriterMultiReaders..." % \ | 
					
						
							|  |  |  |                   self.__class__.__name__ | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         threads = [] | 
					
						
							|  |  |  |         for x in range(self.writers): | 
					
						
							|  |  |  |             wt = Thread(target = self.writerThread, | 
					
						
							|  |  |  |                         args = (self.d, self.records, x), | 
					
						
							|  |  |  |                         name = 'writer %d' % x, | 
					
						
							|  |  |  |                         )#verbose = verbose) | 
					
						
							|  |  |  |             threads.append(wt) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for x in range(self.readers): | 
					
						
							|  |  |  |             rt = Thread(target = self.readerThread, | 
					
						
							|  |  |  |                         args = (self.d, x), | 
					
						
							|  |  |  |                         name = 'reader %d' % x, | 
					
						
							|  |  |  |                         )#verbose = verbose) | 
					
						
							|  |  |  |             threads.append(rt) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for t in threads: | 
					
						
							|  |  |  |             t.start() | 
					
						
							|  |  |  |         for t in threads: | 
					
						
							|  |  |  |             t.join() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def writerThread(self, d, howMany, writerNum): | 
					
						
							|  |  |  |         #time.sleep(0.01 * writerNum + 0.01) | 
					
						
							|  |  |  |         name = currentThread().getName() | 
					
						
							| 
									
										
										
										
											2003-01-10 19:03:29 +00:00
										 |  |  |         start = howMany * writerNum | 
					
						
							|  |  |  |         stop = howMany * (writerNum + 1) - 1 | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  |         if verbose: | 
					
						
							|  |  |  |             print "%s: creating records %d - %d" % (name, start, stop) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for x in range(start, stop): | 
					
						
							|  |  |  |             key = '%04d' % x | 
					
						
							| 
									
										
										
										
											2002-12-30 20:53:52 +00:00
										 |  |  |             dbutils.DeadlockWrap(d.put, key, self.makeData(key), | 
					
						
							|  |  |  |                                  max_retries=12) | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  |             if verbose and x % 100 == 0: | 
					
						
							|  |  |  |                 print "%s: records %d - %d finished" % (name, start, x) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-01-10 19:03:29 +00:00
										 |  |  |         if verbose: | 
					
						
							|  |  |  |             print "%s: finished creating records" % name | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | ##         # Each write-cursor will be exclusive, the only one that can update the DB... | 
					
						
							|  |  |  | ##         if verbose: print "%s: deleting a few records" % name | 
					
						
							|  |  |  | ##         c = d.cursor(flags = db.DB_WRITECURSOR) | 
					
						
							|  |  |  | ##         for x in range(10): | 
					
						
							|  |  |  | ##             key = int(random() * howMany) + start | 
					
						
							|  |  |  | ##             key = '%04d' % key | 
					
						
							|  |  |  | ##             if d.has_key(key): | 
					
						
							|  |  |  | ##                 c.set(key) | 
					
						
							|  |  |  | ##                 c.delete() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ##         c.close() | 
					
						
							| 
									
										
										
										
											2003-01-10 19:03:29 +00:00
										 |  |  |         if verbose: | 
					
						
							|  |  |  |             print "%s: thread finished" % name | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def readerThread(self, d, readerNum): | 
					
						
							|  |  |  |         time.sleep(0.01 * readerNum) | 
					
						
							|  |  |  |         name = currentThread().getName() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for loop in range(5): | 
					
						
							|  |  |  |             c = d.cursor() | 
					
						
							|  |  |  |             count = 0 | 
					
						
							|  |  |  |             rec = c.first() | 
					
						
							|  |  |  |             while rec: | 
					
						
							| 
									
										
										
										
											2003-01-10 19:03:29 +00:00
										 |  |  |                 count += 1 | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  |                 key, data = rec | 
					
						
							| 
									
										
										
										
											2003-01-10 19:03:29 +00:00
										 |  |  |                 self.assertEqual(self.makeData(key), data) | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  |                 rec = c.next() | 
					
						
							| 
									
										
										
										
											2003-01-10 19:03:29 +00:00
										 |  |  |             if verbose: | 
					
						
							|  |  |  |                 print "%s: found %d records" % (name, count) | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  |             c.close() | 
					
						
							|  |  |  |             time.sleep(0.05) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-01-10 19:03:29 +00:00
										 |  |  |         if verbose: | 
					
						
							|  |  |  |             print "%s: thread finished" % name | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class BTreeConcurrentDataStore(ConcurrentDataStoreBase): | 
					
						
							|  |  |  |     dbtype  = db.DB_BTREE | 
					
						
							|  |  |  |     writers = 2 | 
					
						
							|  |  |  |     readers = 10 | 
					
						
							|  |  |  |     records = 1000 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class HashConcurrentDataStore(ConcurrentDataStoreBase): | 
					
						
							|  |  |  |     dbtype  = db.DB_HASH | 
					
						
							|  |  |  |     writers = 2 | 
					
						
							|  |  |  |     readers = 10 | 
					
						
							|  |  |  |     records = 1000 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-01-10 19:03:29 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  | #---------------------------------------------------------------------- | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class SimpleThreadedBase(BaseThreadedTestCase): | 
					
						
							|  |  |  |     dbopenflags = db.DB_THREAD | 
					
						
							|  |  |  |     envflags    = db.DB_THREAD | db.DB_INIT_MPOOL | db.DB_INIT_LOCK | 
					
						
							|  |  |  |     readers = 5 | 
					
						
							|  |  |  |     writers = 3 | 
					
						
							|  |  |  |     records = 1000 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def setEnvOpts(self): | 
					
						
							|  |  |  |         self.env.set_lk_detect(db.DB_LOCK_DEFAULT) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test02_SimpleLocks(self): | 
					
						
							|  |  |  |         if verbose: | 
					
						
							|  |  |  |             print '\n', '-=' * 30 | 
					
						
							|  |  |  |             print "Running %s.test02_SimpleLocks..." % self.__class__.__name__ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         threads = [] | 
					
						
							|  |  |  |         for x in range(self.writers): | 
					
						
							|  |  |  |             wt = Thread(target = self.writerThread, | 
					
						
							|  |  |  |                         args = (self.d, self.records, x), | 
					
						
							|  |  |  |                         name = 'writer %d' % x, | 
					
						
							|  |  |  |                         )#verbose = verbose) | 
					
						
							|  |  |  |             threads.append(wt) | 
					
						
							|  |  |  |         for x in range(self.readers): | 
					
						
							|  |  |  |             rt = Thread(target = self.readerThread, | 
					
						
							|  |  |  |                         args = (self.d, x), | 
					
						
							|  |  |  |                         name = 'reader %d' % x, | 
					
						
							|  |  |  |                         )#verbose = verbose) | 
					
						
							|  |  |  |             threads.append(rt) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for t in threads: | 
					
						
							|  |  |  |             t.start() | 
					
						
							|  |  |  |         for t in threads: | 
					
						
							|  |  |  |             t.join() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def writerThread(self, d, howMany, writerNum): | 
					
						
							|  |  |  |         name = currentThread().getName() | 
					
						
							| 
									
										
										
										
											2003-01-10 19:03:29 +00:00
										 |  |  |         start = howMany * writerNum | 
					
						
							|  |  |  |         stop = howMany * (writerNum + 1) - 1 | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  |         if verbose: | 
					
						
							|  |  |  |             print "%s: creating records %d - %d" % (name, start, stop) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # create a bunch of records | 
					
						
							|  |  |  |         for x in xrange(start, stop): | 
					
						
							|  |  |  |             key = '%04d' % x | 
					
						
							| 
									
										
										
										
											2002-12-30 20:53:52 +00:00
										 |  |  |             dbutils.DeadlockWrap(d.put, key, self.makeData(key), | 
					
						
							|  |  |  |                                  max_retries=12) | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |             if verbose and x % 100 == 0: | 
					
						
							|  |  |  |                 print "%s: records %d - %d finished" % (name, start, x) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # do a bit or reading too | 
					
						
							|  |  |  |             if random() <= 0.05: | 
					
						
							|  |  |  |                 for y in xrange(start, x): | 
					
						
							|  |  |  |                     key = '%04d' % x | 
					
						
							| 
									
										
										
										
											2002-11-23 11:26:07 +00:00
										 |  |  |                     data = dbutils.DeadlockWrap(d.get, key, max_retries=12) | 
					
						
							| 
									
										
										
										
											2003-01-10 19:03:29 +00:00
										 |  |  |                     self.assertEqual(data, self.makeData(key)) | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # flush them | 
					
						
							|  |  |  |         try: | 
					
						
							| 
									
										
										
										
											2002-11-23 11:26:07 +00:00
										 |  |  |             dbutils.DeadlockWrap(d.sync, max_retries=12) | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  |         except db.DBIncompleteError, val: | 
					
						
							|  |  |  |             if verbose: | 
					
						
							|  |  |  |                 print "could not complete sync()..." | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # read them back, deleting a few | 
					
						
							|  |  |  |         for x in xrange(start, stop): | 
					
						
							|  |  |  |             key = '%04d' % x | 
					
						
							| 
									
										
										
										
											2002-11-23 11:26:07 +00:00
										 |  |  |             data = dbutils.DeadlockWrap(d.get, key, max_retries=12) | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  |             if verbose and x % 100 == 0: | 
					
						
							|  |  |  |                 print "%s: fetched record (%s, %s)" % (name, key, data) | 
					
						
							| 
									
										
										
										
											2003-01-10 19:03:29 +00:00
										 |  |  |             self.assertEqual(data, self.makeData(key)) | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  |             if random() <= 0.10: | 
					
						
							| 
									
										
										
										
											2002-11-23 11:26:07 +00:00
										 |  |  |                 dbutils.DeadlockWrap(d.delete, key, max_retries=12) | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  |                 if verbose: | 
					
						
							|  |  |  |                     print "%s: deleted record %s" % (name, key) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-01-10 19:03:29 +00:00
										 |  |  |         if verbose: | 
					
						
							|  |  |  |             print "%s: thread finished" % name | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def readerThread(self, d, readerNum): | 
					
						
							|  |  |  |         time.sleep(0.01 * readerNum) | 
					
						
							|  |  |  |         name = currentThread().getName() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for loop in range(5): | 
					
						
							|  |  |  |             c = d.cursor() | 
					
						
							|  |  |  |             count = 0 | 
					
						
							| 
									
										
										
										
											2003-07-21 23:01:34 +00:00
										 |  |  |             rec = dbutils.DeadlockWrap(c.first, max_retries=10) | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  |             while rec: | 
					
						
							| 
									
										
										
										
											2003-01-10 19:03:29 +00:00
										 |  |  |                 count += 1 | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  |                 key, data = rec | 
					
						
							| 
									
										
										
										
											2003-01-10 19:03:29 +00:00
										 |  |  |                 self.assertEqual(self.makeData(key), data) | 
					
						
							| 
									
										
										
										
											2003-07-21 23:01:34 +00:00
										 |  |  |                 rec = dbutils.DeadlockWrap(c.next, max_retries=10) | 
					
						
							| 
									
										
										
										
											2003-01-10 19:03:29 +00:00
										 |  |  |             if verbose: | 
					
						
							|  |  |  |                 print "%s: found %d records" % (name, count) | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  |             c.close() | 
					
						
							|  |  |  |             time.sleep(0.05) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-01-10 19:03:29 +00:00
										 |  |  |         if verbose: | 
					
						
							|  |  |  |             print "%s: thread finished" % name | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class BTreeSimpleThreaded(SimpleThreadedBase): | 
					
						
							|  |  |  |     dbtype = db.DB_BTREE | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class HashSimpleThreaded(SimpleThreadedBase): | 
					
						
							| 
									
										
										
										
											2002-11-23 11:26:07 +00:00
										 |  |  |     dbtype = db.DB_HASH | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #---------------------------------------------------------------------- | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class ThreadedTransactionsBase(BaseThreadedTestCase): | 
					
						
							| 
									
										
										
										
											2002-12-30 20:53:52 +00:00
										 |  |  |     dbopenflags = db.DB_THREAD | db.DB_AUTO_COMMIT | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  |     envflags    = (db.DB_THREAD | | 
					
						
							|  |  |  |                    db.DB_INIT_MPOOL | | 
					
						
							|  |  |  |                    db.DB_INIT_LOCK | | 
					
						
							|  |  |  |                    db.DB_INIT_LOG | | 
					
						
							|  |  |  |                    db.DB_INIT_TXN | 
					
						
							|  |  |  |                    ) | 
					
						
							|  |  |  |     readers = 0 | 
					
						
							|  |  |  |     writers = 0 | 
					
						
							|  |  |  |     records = 2000 | 
					
						
							|  |  |  |     txnFlag = 0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def setEnvOpts(self): | 
					
						
							|  |  |  |         #self.env.set_lk_detect(db.DB_LOCK_DEFAULT) | 
					
						
							|  |  |  |         pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test03_ThreadedTransactions(self): | 
					
						
							|  |  |  |         if verbose: | 
					
						
							|  |  |  |             print '\n', '-=' * 30 | 
					
						
							| 
									
										
										
										
											2002-12-30 20:53:52 +00:00
										 |  |  |             print "Running %s.test03_ThreadedTransactions..." % \ | 
					
						
							|  |  |  |                   self.__class__.__name__ | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         threads = [] | 
					
						
							|  |  |  |         for x in range(self.writers): | 
					
						
							|  |  |  |             wt = Thread(target = self.writerThread, | 
					
						
							|  |  |  |                         args = (self.d, self.records, x), | 
					
						
							|  |  |  |                         name = 'writer %d' % x, | 
					
						
							|  |  |  |                         )#verbose = verbose) | 
					
						
							|  |  |  |             threads.append(wt) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for x in range(self.readers): | 
					
						
							|  |  |  |             rt = Thread(target = self.readerThread, | 
					
						
							|  |  |  |                         args = (self.d, x), | 
					
						
							|  |  |  |                         name = 'reader %d' % x, | 
					
						
							|  |  |  |                         )#verbose = verbose) | 
					
						
							|  |  |  |             threads.append(rt) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         dt = Thread(target = self.deadlockThread) | 
					
						
							|  |  |  |         dt.start() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for t in threads: | 
					
						
							|  |  |  |             t.start() | 
					
						
							|  |  |  |         for t in threads: | 
					
						
							|  |  |  |             t.join() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-01-10 19:03:29 +00:00
										 |  |  |         self.doLockDetect = False | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  |         dt.join() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def doWrite(self, d, name, start, stop): | 
					
						
							| 
									
										
										
										
											2003-01-10 19:03:29 +00:00
										 |  |  |         finished = False | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  |         while not finished: | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 txn = self.env.txn_begin(None, self.txnFlag) | 
					
						
							|  |  |  |                 for x in range(start, stop): | 
					
						
							|  |  |  |                     key = '%04d' % x | 
					
						
							|  |  |  |                     d.put(key, self.makeData(key), txn) | 
					
						
							|  |  |  |                     if verbose and x % 100 == 0: | 
					
						
							|  |  |  |                         print "%s: records %d - %d finished" % (name, start, x) | 
					
						
							|  |  |  |                 txn.commit() | 
					
						
							| 
									
										
										
										
											2003-01-10 19:03:29 +00:00
										 |  |  |                 finished = True | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  |             except (db.DBLockDeadlockError, db.DBLockNotGrantedError), val: | 
					
						
							|  |  |  |                 if verbose: | 
					
						
							|  |  |  |                     print "%s: Aborting transaction (%s)" % (name, val[1]) | 
					
						
							|  |  |  |                 txn.abort() | 
					
						
							|  |  |  |                 time.sleep(0.05) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def writerThread(self, d, howMany, writerNum): | 
					
						
							|  |  |  |         name = currentThread().getName() | 
					
						
							| 
									
										
										
										
											2003-01-10 19:03:29 +00:00
										 |  |  |         start = howMany * writerNum | 
					
						
							|  |  |  |         stop = howMany * (writerNum + 1) - 1 | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  |         if verbose: | 
					
						
							|  |  |  |             print "%s: creating records %d - %d" % (name, start, stop) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         step = 100 | 
					
						
							|  |  |  |         for x in range(start, stop, step): | 
					
						
							|  |  |  |             self.doWrite(d, name, x, min(stop, x+step)) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-01-10 19:03:29 +00:00
										 |  |  |         if verbose: | 
					
						
							|  |  |  |             print "%s: finished creating records" % name | 
					
						
							|  |  |  |         if verbose: | 
					
						
							|  |  |  |             print "%s: deleting a few records" % name | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-01-10 19:03:29 +00:00
										 |  |  |         finished = False | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  |         while not finished: | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 recs = [] | 
					
						
							|  |  |  |                 txn = self.env.txn_begin(None, self.txnFlag) | 
					
						
							|  |  |  |                 for x in range(10): | 
					
						
							|  |  |  |                     key = int(random() * howMany) + start | 
					
						
							|  |  |  |                     key = '%04d' % key | 
					
						
							|  |  |  |                     data = d.get(key, None, txn, db.DB_RMW) | 
					
						
							|  |  |  |                     if data is not None: | 
					
						
							|  |  |  |                         d.delete(key, txn) | 
					
						
							|  |  |  |                         recs.append(key) | 
					
						
							|  |  |  |                 txn.commit() | 
					
						
							| 
									
										
										
										
											2003-01-10 19:03:29 +00:00
										 |  |  |                 finished = True | 
					
						
							|  |  |  |                 if verbose: | 
					
						
							|  |  |  |                     print "%s: deleted records %s" % (name, recs) | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  |             except (db.DBLockDeadlockError, db.DBLockNotGrantedError), val: | 
					
						
							|  |  |  |                 if verbose: | 
					
						
							|  |  |  |                     print "%s: Aborting transaction (%s)" % (name, val[1]) | 
					
						
							|  |  |  |                 txn.abort() | 
					
						
							|  |  |  |                 time.sleep(0.05) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-01-10 19:03:29 +00:00
										 |  |  |         if verbose: | 
					
						
							|  |  |  |             print "%s: thread finished" % name | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def readerThread(self, d, readerNum): | 
					
						
							|  |  |  |         time.sleep(0.01 * readerNum + 0.05) | 
					
						
							|  |  |  |         name = currentThread().getName() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for loop in range(5): | 
					
						
							| 
									
										
										
										
											2003-01-10 19:03:29 +00:00
										 |  |  |             finished = False | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  |             while not finished: | 
					
						
							|  |  |  |                 try: | 
					
						
							|  |  |  |                     txn = self.env.txn_begin(None, self.txnFlag) | 
					
						
							|  |  |  |                     c = d.cursor(txn) | 
					
						
							|  |  |  |                     count = 0 | 
					
						
							|  |  |  |                     rec = c.first() | 
					
						
							|  |  |  |                     while rec: | 
					
						
							| 
									
										
										
										
											2003-01-10 19:03:29 +00:00
										 |  |  |                         count += 1 | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  |                         key, data = rec | 
					
						
							| 
									
										
										
										
											2003-01-10 19:03:29 +00:00
										 |  |  |                         self.assertEqual(self.makeData(key), data) | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  |                         rec = c.next() | 
					
						
							|  |  |  |                     if verbose: print "%s: found %d records" % (name, count) | 
					
						
							|  |  |  |                     c.close() | 
					
						
							|  |  |  |                     txn.commit() | 
					
						
							| 
									
										
										
										
											2003-01-10 19:03:29 +00:00
										 |  |  |                     finished = True | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  |                 except (db.DBLockDeadlockError, db.DBLockNotGrantedError), val: | 
					
						
							|  |  |  |                     if verbose: | 
					
						
							|  |  |  |                         print "%s: Aborting transaction (%s)" % (name, val[1]) | 
					
						
							|  |  |  |                     c.close() | 
					
						
							|  |  |  |                     txn.abort() | 
					
						
							|  |  |  |                     time.sleep(0.05) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             time.sleep(0.05) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-01-10 19:03:29 +00:00
										 |  |  |         if verbose: | 
					
						
							|  |  |  |             print "%s: thread finished" % name | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def deadlockThread(self): | 
					
						
							| 
									
										
										
										
											2003-01-10 19:03:29 +00:00
										 |  |  |         self.doLockDetect = True | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  |         while self.doLockDetect: | 
					
						
							|  |  |  |             time.sleep(0.5) | 
					
						
							|  |  |  |             try: | 
					
						
							| 
									
										
										
										
											2002-12-30 20:53:52 +00:00
										 |  |  |                 aborted = self.env.lock_detect( | 
					
						
							|  |  |  |                     db.DB_LOCK_RANDOM, db.DB_LOCK_CONFLICT) | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  |                 if verbose and aborted: | 
					
						
							| 
									
										
										
										
											2002-12-30 20:53:52 +00:00
										 |  |  |                     print "deadlock: Aborted %d deadlocked transaction(s)" \ | 
					
						
							|  |  |  |                           % aborted | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  |             except db.DBError: | 
					
						
							|  |  |  |                 pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class BTreeThreadedTransactions(ThreadedTransactionsBase): | 
					
						
							|  |  |  |     dbtype = db.DB_BTREE | 
					
						
							|  |  |  |     writers = 3 | 
					
						
							|  |  |  |     readers = 5 | 
					
						
							|  |  |  |     records = 2000 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class HashThreadedTransactions(ThreadedTransactionsBase): | 
					
						
							|  |  |  |     dbtype = db.DB_HASH | 
					
						
							|  |  |  |     writers = 1 | 
					
						
							|  |  |  |     readers = 5 | 
					
						
							|  |  |  |     records = 2000 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class BTreeThreadedNoWaitTransactions(ThreadedTransactionsBase): | 
					
						
							|  |  |  |     dbtype = db.DB_BTREE | 
					
						
							|  |  |  |     writers = 3 | 
					
						
							|  |  |  |     readers = 5 | 
					
						
							|  |  |  |     records = 2000 | 
					
						
							|  |  |  |     txnFlag = db.DB_TXN_NOWAIT | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class HashThreadedNoWaitTransactions(ThreadedTransactionsBase): | 
					
						
							|  |  |  |     dbtype = db.DB_HASH | 
					
						
							|  |  |  |     writers = 1 | 
					
						
							|  |  |  |     readers = 5 | 
					
						
							|  |  |  |     records = 2000 | 
					
						
							|  |  |  |     txnFlag = db.DB_TXN_NOWAIT | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #---------------------------------------------------------------------- | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-12-30 20:53:52 +00:00
										 |  |  | def test_suite(): | 
					
						
							|  |  |  |     suite = unittest.TestSuite() | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if have_threads: | 
					
						
							| 
									
										
										
										
											2002-12-30 20:53:52 +00:00
										 |  |  |         suite.addTest(unittest.makeSuite(BTreeConcurrentDataStore)) | 
					
						
							|  |  |  |         suite.addTest(unittest.makeSuite(HashConcurrentDataStore)) | 
					
						
							|  |  |  |         suite.addTest(unittest.makeSuite(BTreeSimpleThreaded)) | 
					
						
							|  |  |  |         suite.addTest(unittest.makeSuite(HashSimpleThreaded)) | 
					
						
							|  |  |  |         suite.addTest(unittest.makeSuite(BTreeThreadedTransactions)) | 
					
						
							|  |  |  |         suite.addTest(unittest.makeSuite(HashThreadedTransactions)) | 
					
						
							|  |  |  |         suite.addTest(unittest.makeSuite(BTreeThreadedNoWaitTransactions)) | 
					
						
							|  |  |  |         suite.addTest(unittest.makeSuite(HashThreadedNoWaitTransactions)) | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         print "Threads not available, skipping thread tests." | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-12-30 20:53:52 +00:00
										 |  |  |     return suite | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | if __name__ == '__main__': | 
					
						
							| 
									
										
										
										
											2002-12-30 20:53:52 +00:00
										 |  |  |     unittest.main(defaultTest='test_suite') |