| 
									
										
										
										
											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 | 
					
						
							| 
									
										
										
										
											2004-08-08 00:54:21 +00:00
										 |  |  | from random import random | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-01-10 19:03:29 +00:00
										 |  |  | DASH = '-' | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-05-06 20:04:08 +00:00
										 |  |  | try: | 
					
						
							|  |  |  |     WindowsError | 
					
						
							|  |  |  | except NameError: | 
					
						
							|  |  |  |     class WindowsError(Exception): | 
					
						
							|  |  |  |         pass | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  | import unittest | 
					
						
							| 
									
										
										
										
											2008-08-31 14:00:51 +00:00
										 |  |  | from test_all import db, dbutils, test_support, verbose, have_threads, \ | 
					
						
							|  |  |  |         get_new_environment_path, get_new_database_path | 
					
						
							| 
									
										
										
										
											2008-07-23 11:38:42 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | if have_threads : | 
					
						
							| 
									
										
										
										
											2008-08-31 14:00:51 +00:00
										 |  |  |     from threading import Thread | 
					
						
							|  |  |  |     if sys.version_info[0] < 3 : | 
					
						
							|  |  |  |         from threading import currentThread | 
					
						
							|  |  |  |     else : | 
					
						
							|  |  |  |         from threading import current_thread as currentThread | 
					
						
							| 
									
										
										
										
											2008-03-02 20:00:53 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											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 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-03-22 14:22:26 +00:00
										 |  |  |     if sys.version_info < (2, 4) : | 
					
						
							| 
									
										
										
										
											2008-05-13 20:57:59 +00:00
										 |  |  |         def assertTrue(self, expr, msg=None): | 
					
						
							|  |  |  |             self.failUnless(expr,msg=msg) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  |     def setUp(self): | 
					
						
							| 
									
										
										
										
											2002-11-23 11:26:07 +00:00
										 |  |  |         if verbose: | 
					
						
							|  |  |  |             dbutils._deadlock_VerboseFile = sys.stdout | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-13 20:57:59 +00:00
										 |  |  |         self.homeDir = get_new_environment_path() | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  |         self.env = db.DBEnv() | 
					
						
							|  |  |  |         self.setEnvOpts() | 
					
						
							| 
									
										
										
										
											2008-05-13 20:57:59 +00:00
										 |  |  |         self.env.open(self.homeDir, self.envflags | db.DB_CREATE) | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         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() | 
					
						
							| 
									
										
										
										
											2008-03-05 05:10:48 +00:00
										 |  |  |         test_support.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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-13 20:57:59 +00:00
										 |  |  |         keys=range(self.records) | 
					
						
							|  |  |  |         import random | 
					
						
							|  |  |  |         random.shuffle(keys) | 
					
						
							| 
									
										
										
										
											2008-07-23 11:38:42 +00:00
										 |  |  |         records_per_writer=self.records//self.writers | 
					
						
							|  |  |  |         readers_per_writer=self.readers//self.writers | 
					
						
							| 
									
										
										
										
											2008-05-13 20:57:59 +00:00
										 |  |  |         self.assertEqual(self.records,self.writers*records_per_writer) | 
					
						
							|  |  |  |         self.assertEqual(self.readers,self.writers*readers_per_writer) | 
					
						
							|  |  |  |         self.assertTrue((records_per_writer%readers_per_writer)==0) | 
					
						
							|  |  |  |         readers = [] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for x in xrange(self.readers): | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  |             rt = Thread(target = self.readerThread, | 
					
						
							|  |  |  |                         args = (self.d, x), | 
					
						
							|  |  |  |                         name = 'reader %d' % x, | 
					
						
							|  |  |  |                         )#verbose = verbose) | 
					
						
							| 
									
										
										
										
											2008-08-31 14:00:51 +00:00
										 |  |  |             if sys.version_info[0] < 3 : | 
					
						
							|  |  |  |                 rt.setDaemon(True) | 
					
						
							|  |  |  |             else : | 
					
						
							|  |  |  |                 rt.daemon = True | 
					
						
							| 
									
										
										
										
											2008-05-13 20:57:59 +00:00
										 |  |  |             readers.append(rt) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         writers=[] | 
					
						
							|  |  |  |         for x in xrange(self.writers): | 
					
						
							|  |  |  |             a=keys[records_per_writer*x:records_per_writer*(x+1)] | 
					
						
							|  |  |  |             a.sort()  # Generate conflicts | 
					
						
							|  |  |  |             b=readers[readers_per_writer*x:readers_per_writer*(x+1)] | 
					
						
							|  |  |  |             wt = Thread(target = self.writerThread, | 
					
						
							|  |  |  |                         args = (self.d, a, b), | 
					
						
							|  |  |  |                         name = 'writer %d' % x, | 
					
						
							|  |  |  |                         )#verbose = verbose) | 
					
						
							|  |  |  |             writers.append(wt) | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-13 20:57:59 +00:00
										 |  |  |         for t in writers: | 
					
						
							| 
									
										
										
										
											2008-08-31 14:00:51 +00:00
										 |  |  |             if sys.version_info[0] < 3 : | 
					
						
							|  |  |  |                 t.setDaemon(True) | 
					
						
							|  |  |  |             else : | 
					
						
							|  |  |  |                 t.daemon = True | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  |             t.start() | 
					
						
							| 
									
										
										
										
											2008-05-13 20:57:59 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         for t in writers: | 
					
						
							|  |  |  |             t.join() | 
					
						
							|  |  |  |         for t in readers: | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  |             t.join() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-13 20:57:59 +00:00
										 |  |  |     def writerThread(self, d, keys, readers): | 
					
						
							| 
									
										
										
										
											2008-08-31 14:00:51 +00:00
										 |  |  |         if sys.version_info[0] < 3 : | 
					
						
							|  |  |  |             name = currentThread().getName() | 
					
						
							|  |  |  |         else : | 
					
						
							|  |  |  |             name = currentThread().name | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  |         if verbose: | 
					
						
							|  |  |  |             print "%s: creating records %d - %d" % (name, start, stop) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-07-23 11:38:42 +00:00
										 |  |  |         count=len(keys)//len(readers) | 
					
						
							| 
									
										
										
										
											2008-05-13 20:57:59 +00:00
										 |  |  |         count2=count | 
					
						
							|  |  |  |         for x in keys : | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  |             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) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-13 20:57:59 +00:00
										 |  |  |             count2-=1 | 
					
						
							|  |  |  |             if not count2 : | 
					
						
							|  |  |  |                 readers.pop().start() | 
					
						
							|  |  |  |                 count2=count | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-01-10 19:03:29 +00:00
										 |  |  |         if verbose: | 
					
						
							|  |  |  |             print "%s: finished creating records" % name | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											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): | 
					
						
							| 
									
										
										
										
											2008-08-31 14:00:51 +00:00
										 |  |  |         if sys.version_info[0] < 3 : | 
					
						
							|  |  |  |             name = currentThread().getName() | 
					
						
							|  |  |  |         else : | 
					
						
							|  |  |  |             name = currentThread().name | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-13 20:57:59 +00:00
										 |  |  |         for i in xrange(5) : | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  |             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() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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 | 
					
						
							| 
									
										
										
										
											2008-05-13 20:57:59 +00:00
										 |  |  |     readers = 10 | 
					
						
							|  |  |  |     writers = 2 | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  |     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__ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-13 20:57:59 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         keys=range(self.records) | 
					
						
							|  |  |  |         import random | 
					
						
							|  |  |  |         random.shuffle(keys) | 
					
						
							| 
									
										
										
										
											2008-07-23 11:38:42 +00:00
										 |  |  |         records_per_writer=self.records//self.writers | 
					
						
							|  |  |  |         readers_per_writer=self.readers//self.writers | 
					
						
							| 
									
										
										
										
											2008-05-13 20:57:59 +00:00
										 |  |  |         self.assertEqual(self.records,self.writers*records_per_writer) | 
					
						
							|  |  |  |         self.assertEqual(self.readers,self.writers*readers_per_writer) | 
					
						
							|  |  |  |         self.assertTrue((records_per_writer%readers_per_writer)==0) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         readers = [] | 
					
						
							|  |  |  |         for x in xrange(self.readers): | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  |             rt = Thread(target = self.readerThread, | 
					
						
							|  |  |  |                         args = (self.d, x), | 
					
						
							|  |  |  |                         name = 'reader %d' % x, | 
					
						
							|  |  |  |                         )#verbose = verbose) | 
					
						
							| 
									
										
										
										
											2008-08-31 14:00:51 +00:00
										 |  |  |             if sys.version_info[0] < 3 : | 
					
						
							|  |  |  |                 rt.setDaemon(True) | 
					
						
							|  |  |  |             else : | 
					
						
							|  |  |  |                 rt.daemon = True | 
					
						
							| 
									
										
										
										
											2008-05-13 20:57:59 +00:00
										 |  |  |             readers.append(rt) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         writers = [] | 
					
						
							|  |  |  |         for x in xrange(self.writers): | 
					
						
							|  |  |  |             a=keys[records_per_writer*x:records_per_writer*(x+1)] | 
					
						
							|  |  |  |             a.sort()  # Generate conflicts | 
					
						
							|  |  |  |             b=readers[readers_per_writer*x:readers_per_writer*(x+1)] | 
					
						
							|  |  |  |             wt = Thread(target = self.writerThread, | 
					
						
							|  |  |  |                         args = (self.d, a, b), | 
					
						
							|  |  |  |                         name = 'writer %d' % x, | 
					
						
							|  |  |  |                         )#verbose = verbose) | 
					
						
							|  |  |  |             writers.append(wt) | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-13 20:57:59 +00:00
										 |  |  |         for t in writers: | 
					
						
							| 
									
										
										
										
											2008-08-31 14:00:51 +00:00
										 |  |  |             if sys.version_info[0] < 3 : | 
					
						
							|  |  |  |                 t.setDaemon(True) | 
					
						
							|  |  |  |             else : | 
					
						
							|  |  |  |                 t.daemon = True | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  |             t.start() | 
					
						
							| 
									
										
										
										
											2008-05-13 20:57:59 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         for t in writers: | 
					
						
							|  |  |  |             t.join() | 
					
						
							|  |  |  |         for t in readers: | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  |             t.join() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-13 20:57:59 +00:00
										 |  |  |     def writerThread(self, d, keys, readers): | 
					
						
							| 
									
										
										
										
											2008-08-31 14:00:51 +00:00
										 |  |  |         if sys.version_info[0] < 3 : | 
					
						
							|  |  |  |             name = currentThread().getName() | 
					
						
							|  |  |  |         else : | 
					
						
							|  |  |  |             name = currentThread().name | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  |         if verbose: | 
					
						
							|  |  |  |             print "%s: creating records %d - %d" % (name, start, stop) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-07-23 11:38:42 +00:00
										 |  |  |         count=len(keys)//len(readers) | 
					
						
							| 
									
										
										
										
											2008-05-13 20:57:59 +00:00
										 |  |  |         count2=count | 
					
						
							|  |  |  |         for x in keys : | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  |             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) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-13 20:57:59 +00:00
										 |  |  |             count2-=1 | 
					
						
							|  |  |  |             if not count2 : | 
					
						
							|  |  |  |                 readers.pop().start() | 
					
						
							|  |  |  |                 count2=count | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											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): | 
					
						
							| 
									
										
										
										
											2008-08-31 14:00:51 +00:00
										 |  |  |         if sys.version_info[0] < 3 : | 
					
						
							|  |  |  |             name = currentThread().getName() | 
					
						
							|  |  |  |         else : | 
					
						
							|  |  |  |             name = currentThread().name | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-13 20:57:59 +00:00
										 |  |  |         c = d.cursor() | 
					
						
							|  |  |  |         count = 0 | 
					
						
							|  |  |  |         rec = dbutils.DeadlockWrap(c.first, max_retries=10) | 
					
						
							|  |  |  |         while rec: | 
					
						
							|  |  |  |             count += 1 | 
					
						
							|  |  |  |             key, data = rec | 
					
						
							|  |  |  |             self.assertEqual(self.makeData(key), data) | 
					
						
							|  |  |  |             rec = dbutils.DeadlockWrap(c.next, max_retries=10) | 
					
						
							|  |  |  |         if verbose: | 
					
						
							|  |  |  |             print "%s: found %d records" % (name, count) | 
					
						
							|  |  |  |         c.close() | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-13 20:57:59 +00:00
										 |  |  |         keys=range(self.records) | 
					
						
							|  |  |  |         import random | 
					
						
							|  |  |  |         random.shuffle(keys) | 
					
						
							| 
									
										
										
										
											2008-07-23 11:38:42 +00:00
										 |  |  |         records_per_writer=self.records//self.writers | 
					
						
							|  |  |  |         readers_per_writer=self.readers//self.writers | 
					
						
							| 
									
										
										
										
											2008-05-13 20:57:59 +00:00
										 |  |  |         self.assertEqual(self.records,self.writers*records_per_writer) | 
					
						
							|  |  |  |         self.assertEqual(self.readers,self.writers*readers_per_writer) | 
					
						
							|  |  |  |         self.assertTrue((records_per_writer%readers_per_writer)==0) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         readers=[] | 
					
						
							|  |  |  |         for x in xrange(self.readers): | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  |             rt = Thread(target = self.readerThread, | 
					
						
							|  |  |  |                         args = (self.d, x), | 
					
						
							|  |  |  |                         name = 'reader %d' % x, | 
					
						
							|  |  |  |                         )#verbose = verbose) | 
					
						
							| 
									
										
										
										
											2008-08-31 14:00:51 +00:00
										 |  |  |             if sys.version_info[0] < 3 : | 
					
						
							|  |  |  |                 rt.setDaemon(True) | 
					
						
							|  |  |  |             else : | 
					
						
							|  |  |  |                 rt.daemon = True | 
					
						
							| 
									
										
										
										
											2008-05-13 20:57:59 +00:00
										 |  |  |             readers.append(rt) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         writers = [] | 
					
						
							|  |  |  |         for x in xrange(self.writers): | 
					
						
							|  |  |  |             a=keys[records_per_writer*x:records_per_writer*(x+1)] | 
					
						
							|  |  |  |             b=readers[readers_per_writer*x:readers_per_writer*(x+1)] | 
					
						
							|  |  |  |             wt = Thread(target = self.writerThread, | 
					
						
							|  |  |  |                         args = (self.d, a, b), | 
					
						
							|  |  |  |                         name = 'writer %d' % x, | 
					
						
							|  |  |  |                         )#verbose = verbose) | 
					
						
							|  |  |  |             writers.append(wt) | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         dt = Thread(target = self.deadlockThread) | 
					
						
							| 
									
										
										
										
											2008-08-31 14:00:51 +00:00
										 |  |  |         if sys.version_info[0] < 3 : | 
					
						
							|  |  |  |             dt.setDaemon(True) | 
					
						
							|  |  |  |         else : | 
					
						
							|  |  |  |             dt.daemon = True | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  |         dt.start() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-13 20:57:59 +00:00
										 |  |  |         for t in writers: | 
					
						
							| 
									
										
										
										
											2008-08-31 14:00:51 +00:00
										 |  |  |             if sys.version_info[0] < 3 : | 
					
						
							|  |  |  |                 t.setDaemon(True) | 
					
						
							|  |  |  |             else : | 
					
						
							|  |  |  |                 t.daemon = True | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  |             t.start() | 
					
						
							| 
									
										
										
										
											2008-05-13 20:57:59 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         for t in writers: | 
					
						
							|  |  |  |             t.join() | 
					
						
							|  |  |  |         for t in readers: | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  |             t.join() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-01-10 19:03:29 +00:00
										 |  |  |         self.doLockDetect = False | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  |         dt.join() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-13 20:57:59 +00:00
										 |  |  |     def writerThread(self, d, keys, readers): | 
					
						
							| 
									
										
										
										
											2008-08-31 14:00:51 +00:00
										 |  |  |         if sys.version_info[0] < 3 : | 
					
						
							|  |  |  |             name = currentThread().getName() | 
					
						
							|  |  |  |         else : | 
					
						
							|  |  |  |             name = currentThread().name | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-07-23 11:38:42 +00:00
										 |  |  |         count=len(keys)//len(readers) | 
					
						
							| 
									
										
										
										
											2008-05-13 20:57:59 +00:00
										 |  |  |         while len(keys): | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  |             try: | 
					
						
							|  |  |  |                 txn = self.env.txn_begin(None, self.txnFlag) | 
					
						
							| 
									
										
										
										
											2008-05-13 20:57:59 +00:00
										 |  |  |                 keys2=keys[:count] | 
					
						
							|  |  |  |                 for x in keys2 : | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  |                     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() | 
					
						
							| 
									
										
										
										
											2008-05-13 20:57:59 +00:00
										 |  |  |                 keys=keys[count:] | 
					
						
							|  |  |  |                 readers.pop().start() | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  |             except (db.DBLockDeadlockError, db.DBLockNotGrantedError), val: | 
					
						
							|  |  |  |                 if verbose: | 
					
						
							| 
									
										
										
										
											2010-03-22 14:22:26 +00:00
										 |  |  |                     if sys.version_info < (2, 6) : | 
					
						
							|  |  |  |                         print "%s: Aborting transaction (%s)" % (name, val[1]) | 
					
						
							|  |  |  |                     else : | 
					
						
							|  |  |  |                         print "%s: Aborting transaction (%s)" % (name, | 
					
						
							|  |  |  |                                 val.args[1]) | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  |                 txn.abort() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if verbose: | 
					
						
							| 
									
										
										
										
											2008-05-13 20:57:59 +00:00
										 |  |  |             print "%s: thread finished" % name | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-13 20:57:59 +00:00
										 |  |  |     def readerThread(self, d, readerNum): | 
					
						
							| 
									
										
										
										
											2008-08-31 14:00:51 +00:00
										 |  |  |         if sys.version_info[0] < 3 : | 
					
						
							|  |  |  |             name = currentThread().getName() | 
					
						
							|  |  |  |         else : | 
					
						
							|  |  |  |             name = currentThread().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: | 
					
						
							|  |  |  |                 txn = self.env.txn_begin(None, self.txnFlag) | 
					
						
							| 
									
										
										
										
											2008-05-13 20:57:59 +00:00
										 |  |  |                 c = d.cursor(txn) | 
					
						
							|  |  |  |                 count = 0 | 
					
						
							|  |  |  |                 rec = c.first() | 
					
						
							|  |  |  |                 while rec: | 
					
						
							|  |  |  |                     count += 1 | 
					
						
							|  |  |  |                     key, data = rec | 
					
						
							|  |  |  |                     self.assertEqual(self.makeData(key), data) | 
					
						
							|  |  |  |                     rec = c.next() | 
					
						
							|  |  |  |                 if verbose: print "%s: found %d records" % (name, count) | 
					
						
							|  |  |  |                 c.close() | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  |                 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: | 
					
						
							| 
									
										
										
										
											2010-03-22 14:22:26 +00:00
										 |  |  |                     if sys.version_info < (2, 6) : | 
					
						
							|  |  |  |                         print "%s: Aborting transaction (%s)" % (name, val[1]) | 
					
						
							|  |  |  |                     else : | 
					
						
							|  |  |  |                         print "%s: Aborting transaction (%s)" % (name, | 
					
						
							|  |  |  |                                 val.args[1]) | 
					
						
							| 
									
										
										
										
											2008-05-13 20:57:59 +00:00
										 |  |  |                 c.close() | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  |                 txn.abort() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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: | 
					
						
							| 
									
										
										
										
											2008-05-13 20:57:59 +00:00
										 |  |  |             time.sleep(0.05) | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  |             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 | 
					
						
							| 
									
										
										
										
											2008-05-13 20:57:59 +00:00
										 |  |  |     writers = 2 | 
					
						
							|  |  |  |     readers = 10 | 
					
						
							|  |  |  |     records = 1000 | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | class HashThreadedTransactions(ThreadedTransactionsBase): | 
					
						
							|  |  |  |     dbtype = db.DB_HASH | 
					
						
							| 
									
										
										
										
											2008-05-13 20:57:59 +00:00
										 |  |  |     writers = 2 | 
					
						
							|  |  |  |     readers = 10 | 
					
						
							|  |  |  |     records = 1000 | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | class BTreeThreadedNoWaitTransactions(ThreadedTransactionsBase): | 
					
						
							|  |  |  |     dbtype = db.DB_BTREE | 
					
						
							| 
									
										
										
										
											2008-05-13 20:57:59 +00:00
										 |  |  |     writers = 2 | 
					
						
							|  |  |  |     readers = 10 | 
					
						
							|  |  |  |     records = 1000 | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  |     txnFlag = db.DB_TXN_NOWAIT | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class HashThreadedNoWaitTransactions(ThreadedTransactionsBase): | 
					
						
							|  |  |  |     dbtype = db.DB_HASH | 
					
						
							| 
									
										
										
										
											2008-05-13 20:57:59 +00:00
										 |  |  |     writers = 2 | 
					
						
							|  |  |  |     readers = 10 | 
					
						
							|  |  |  |     records = 1000 | 
					
						
							| 
									
										
										
										
											2002-11-19 17:47:07 +00:00
										 |  |  |     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') |