2004-06-11 00:12:35 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								/*
  
						 
					
						
							
								
									
										
										
										
											2005-09-14 20:46:50 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								 *  Asterisk  - -  An  open  source  telephony  toolkit . 
							 
						 
					
						
							
								
									
										
										
										
											2004-06-11 00:12:35 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								 * 
							 
						 
					
						
							
								
									
										
										
										
											2012-02-27 15:35:10 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								 *  Copyright  ( C )  1999  -  2012 ,  Digium ,  Inc . 
							 
						 
					
						
							
								
									
										
										
										
											2004-06-11 00:12:35 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								 * 
							 
						 
					
						
							
								
									
										
										
										
											2004-10-05 06:46:11 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								 *  Mark  Spencer  < markster @ digium . com > 
							 
						 
					
						
							
								
									
										
										
										
											2004-06-11 00:12:35 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								 * 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  res_odbc . c  < ODBC  resource  manager > 
							 
						 
					
						
							
								
									
										
										
										
											2005-01-21 07:06:25 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								 *  Copyright  ( C )  2004  -  2005  Anthony  Minessale  II  < anthmct @ yahoo . com > 
							 
						 
					
						
							
								
									
										
										
										
											2005-09-14 20:46:50 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								 * 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  See  http : //www.asterisk.org for more information about
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  the  Asterisk  project .  Please  do  not  directly  contact 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  any  of  the  maintainers  of  this  project  for  assistance ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  the  project  provides  a  web  site ,  mailing  lists  and  IRC 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  channels  for  your  use . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 * 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  This  program  is  free  software ,  distributed  under  the  terms  of 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  the  GNU  General  Public  License  Version  2.  See  the  LICENSE  file 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  at  the  top  of  the  source  tree . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2005-10-24 20:12:06 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								/*! \file
  
						 
					
						
							
								
									
										
										
										
											2005-09-14 20:46:50 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								 * 
							 
						 
					
						
							
								
									
										
										
										
											2005-10-24 20:12:06 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								 *  \ brief  ODBC  resource  manager 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  
							 
						 
					
						
							
								
									
										
										
										
											2005-12-30 21:18:06 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								 *  \ author  Mark  Spencer  < markster @ digium . com > 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  \ author  Anthony  Minessale  II  < anthmct @ yahoo . com > 
							 
						 
					
						
							
								
									
										
										
										
											2009-02-19 00:26:01 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								 *  \ author  Tilghman  Lesher  < tilghman @ digium . com > 
							 
						 
					
						
							
								
									
										
										
										
											2005-09-14 20:46:50 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								 * 
							 
						 
					
						
							
								
									
										
										
										
											2005-12-30 21:18:06 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								 *  \ arg  See  also :  \ ref  cdr_odbc 
							 
						 
					
						
							
								
									
										
										
										
											2004-06-11 00:12:35 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								 */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2012-10-14 21:44:27 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								/*! \li \ref res_odbc.c uses the configuration file \ref res_odbc.conf
  
						 
					
						
							
								
									
										
										
										
											2012-10-01 23:24:10 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								 *  \ addtogroup  configuration_file  Configuration  Files 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								/*! 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  \ page  res_odbc . conf  res_odbc . conf 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  \ verbinclude  res_odbc . conf . sample 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2006-04-24 17:11:45 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								/*** MODULEINFO
  
						 
					
						
							
								
									
										
										
										
											2009-01-15 20:18:53 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									< depend > generic_odbc < / depend > 
							 
						 
					
						
							
								
									
										
										
										
											2007-06-18 16:35:51 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									< depend > ltdl < / depend > 
							 
						 
					
						
							
								
									
										
										
										
											2011-07-14 20:28:54 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									< support_level > core < / support_level > 
							 
						 
					
						
							
								
									
										
										
										
											2006-04-24 17:11:45 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								 * * */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2006-06-07 18:54:56 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								# include  "asterisk.h" 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
											 
										
											
												git migration: Refactor the ASTERISK_FILE_VERSION macro
Git does not support the ability to replace a token with a version
string during check-in. While it does have support for replacing a
token on clone, this is somewhat sub-optimal: the token is replaced
with the object hash, which is not particularly easy for human
consumption. What's more, in practice, the source file version was often
not terribly useful. Generally, when triaging bugs, the overall version
of Asterisk is far more useful than an individual SVN version of a file. As a
result, this patch removes Asterisk's support for showing source file
versions.
Specifically, it does the following:
* Rename ASTERISK_FILE_VERSION macro to ASTERISK_REGISTER_FILE, and
  remove passing the version in with the macro. Other facilities
  than 'core show file version' make use of the file names, such as
  setting a debug level only on a specific file. As such, the act of
  registering source files with the Asterisk core still has use. The
  macro rename now reflects the new macro purpose.
* main/asterisk:
  - Refactor the file_version structure to reflect that it no longer
    tracks a version field.
  - Remove the "core show file version" CLI command. Without the file
    version, it is no longer useful.
  - Remove the ast_file_version_find function. The file version is no
    longer tracked.
  - Rename ast_register_file_version/ast_unregister_file_version to
    ast_register_file/ast_unregister_file, respectively.
* main/manager: Remove value from the Version key of the ModuleCheck
  Action. The actual key itself has not been removed, as doing so would
  absolutely constitute a backwards incompatible change. However, since
  the file version is no longer tracked, there is no need to attempt to
  include it in the Version key.
* UPGRADE: Add notes for:
  - Modification to the ModuleCheck AMI Action
  - Removal of the "core show file version" CLI command
Change-Id: I6cf0ff280e1668bf4957dc21f32a5ff43444a40e
											 
										 
										
											2015-04-11 21:38:22 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								ASTERISK_REGISTER_FILE ( )  
						 
					
						
							
								
									
										
										
										
											2006-06-07 18:54:56 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2005-04-21 06:02:45 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								# include  "asterisk/file.h" 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# include  "asterisk/channel.h" 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# include  "asterisk/config.h" 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# include  "asterisk/pbx.h" 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# include  "asterisk/module.h" 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# include  "asterisk/cli.h" 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# include  "asterisk/lock.h" 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# include  "asterisk/res_odbc.h" 
  
						 
					
						
							
								
									
										
										
										
											2008-01-21 18:15:57 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								# include  "asterisk/time.h" 
  
						 
					
						
							
								
									
										
										
										
											2008-05-05 23:38:15 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								# include  "asterisk/astobj2.h" 
  
						 
					
						
							
								
									
										
										
										
											2009-02-19 00:26:01 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								# include  "asterisk/app.h" 
  
						 
					
						
							
								
									
										
										
										
											2009-01-19 21:42:46 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								# include  "asterisk/strings.h" 
  
						 
					
						
							
								
									
										
										
										
											2009-02-19 00:26:01 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								# include  "asterisk/threadstorage.h" 
  
						 
					
						
							
								
									
										
										
										
											2010-07-08 14:48:42 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								# include  "asterisk/data.h" 
  
						 
					
						
							
								
									
										
										
										
											2009-02-19 00:26:01 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2006-04-18 18:16:32 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								struct  odbc_class  
						 
					
						
							
								
									
										
										
										
											2004-07-08 19:58:26 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
									
										
										
										
											2006-04-18 18:16:32 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									AST_LIST_ENTRY ( odbc_class )  list ; 
							 
						 
					
						
							
								
									
										
										
										
											2004-07-08 19:58:26 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									char  name [ 80 ] ; 
							 
						 
					
						
							
								
									
										
										
										
											2006-04-18 18:16:32 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									char  dsn [ 80 ] ; 
							 
						 
					
						
							
								
									
										
										
										
											2008-01-18 06:52:18 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									char  * username ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									char  * password ; 
							 
						 
					
						
							
								
									
										
										
										
											2008-05-05 23:38:15 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									char  * sanitysql ; 
							 
						 
					
						
							
								
									
										
										
										
											2006-04-18 18:16:32 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									SQLHENV  env ; 
							 
						 
					
						
							
								
									
										
										
										
											2009-02-19 00:26:01 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									unsigned  int  delme : 1 ;                 /*!< Purge the class */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									unsigned  int  backslash_is_escape : 1 ;   /*!< On this database, the backslash is a native escape sequence */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									unsigned  int  forcecommit : 1 ;           /*!< Should uncommitted transactions be auto-committed on handle release? */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									unsigned  int  isolation ;               /*!< Flags for how the DB should deal with data in other, uncommitted transactions */ 
							 
						 
					
						
							
								
									
										
										
										
											2010-07-23 16:19:21 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									unsigned  int  conntimeout ;             /*!< Maximum time the connection process should take */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/*! When a connection fails, cache that failure for how long? */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									struct  timeval  negative_connection_cache ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/*! When a connection fails, when did that last occur? */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									struct  timeval  last_negative_connect ; 
							 
						 
					
						
							
								
									
										
										
										
											2004-06-11 00:12:35 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								} ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2009-03-18 02:39:36 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								static  struct  ao2_container  * class_container ;  
						 
					
						
							
								
									
										
										
										
											2004-06-11 00:12:35 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2008-06-10 21:14:58 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								static  AST_RWLIST_HEAD_STATIC ( odbc_tables ,  odbc_cache_tables ) ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2006-04-18 18:16:32 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								static  odbc_status  odbc_obj_connect ( struct  odbc_obj  * obj ) ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  odbc_status  odbc_obj_disconnect ( struct  odbc_obj  * obj ) ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  int  odbc_register_class ( struct  odbc_class  * class ,  int  connect ) ;  
						 
					
						
							
								
									
										
										
										
											2009-02-19 00:26:01 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								AST_THREADSTORAGE ( errors_buf ) ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								struct  odbc_txn_frame  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									AST_LIST_ENTRY ( odbc_txn_frame )  list ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									struct  ast_channel  * owner ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									struct  odbc_obj  * obj ;         /*!< Database handle within which transacted statements are run */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/*!\brief Is this record the current active transaction within the channel?
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 *  Note  that  the  active  flag  is  really  only  necessary  for  statements  which 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 *  are  triggered  from  the  dialplan ,  as  there  isn ' t  a  direct  correlation 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 *  between  multiple  statements .   Applications  wishing  to  use  transactions 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 *  may  simply  perform  each  statement  on  the  same  odbc_obj ,  which  keeps  the 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 *  transaction  persistent . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									unsigned  int  active : 1 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									unsigned  int  forcecommit : 1 ;      /*!< Should uncommitted transactions be auto-committed on handle release? */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									unsigned  int  isolation ;          /*!< Flags for how the DB should deal with data in other, uncommitted transactions */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									char  name [ 0 ] ;                    /*!< Name of this transaction ID */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								} ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2010-07-08 14:48:42 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								# define DATA_EXPORT_ODBC_CLASS(MEMBER)				\ 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									MEMBER ( odbc_class ,  name ,  AST_DATA_STRING ) 		\
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									MEMBER ( odbc_class ,  dsn ,  AST_DATA_STRING ) 		\
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									MEMBER ( odbc_class ,  username ,  AST_DATA_STRING ) 		\
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									MEMBER ( odbc_class ,  password ,  AST_DATA_PASSWORD ) 		\
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									MEMBER ( odbc_class ,  forcecommit ,  AST_DATA_BOOLEAN ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								AST_DATA_STRUCTURE ( odbc_class ,  DATA_EXPORT_ODBC_CLASS ) ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
											 
										
											
												res_odbc: Remove connection management
Asterisk by default will create a single database connection and share
it among all threads that attempt to access the database. In previous
versions of Asterisk, this was tolerable, because the most used channel
driver, chan_sip, mostly accessed the database from a single thread.
With PJSIP, however, many threads may be attempting to perform database
operations, and there is the potential for many more database accesses,
meaning the concurrency is a horrible bottleneck if only one connection
is shared.
Asterisk has a connection pooling facility built into it, but the
implementation has flaws. For one, there is a strict limit on the number
of simultaneous connections that could be made to the database. Anything
beyond the maximum would result in a failed operation. Attempting to
predict what the maximum should be is nearly impossible even for someone
intimately familiar with Asterisk's threading model. In addition, use of
transactions in the dialplan can cause some severe bugs if connection
pooling is enabled.
This commit seeks to fix the concurrency problem by removing all
connection management code from Asterisk and leaving that to the
underlying unixODBC code instead. Now, Asterisk does not share a single
connection, nor does it try to maintain a connection pool. Instead, all
Asterisk ever does is request a connection from unixODBC and allow
unixODBC to either allocate those connections or retrieve them from a
pool.
Doing this has a bit of a ripple effect. For one, since connections are
not long-lived objects, several of the safeguards that previously
existed have been removed. We don't have to worry about trying to use a
connection that has gone stale. In every case, when we request a
connection, it has just been made and we don't need to perform any
sanity checks to be sure it's still active.
Another major player affected by this change is transactions.
Transactions and their respective connections were so tightly coupled
that it was almost pornographic. This code change moves
transaction-related code to its own file separate from the core ODBC
functionality. This way, the core of ODBC does not even have to know
that transactions exist.
In making this large change, I had to look at a lot of code and
understand it. When making this change, I discovered several places
where the behavior is definitely not ideal, but it seemed outside the
scope of this change to be fixing it. Instead, any place where I saw
some sort of room for improvement has had a XXX comment added explaining
what could be altered to improve it.
Change-Id: I37a84def5ea4ddf93868ce8105f39de078297fbf
											 
										 
										
											2015-12-23 15:07:05 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								const  char  * ast_odbc_isolation2text ( int  iso )  
						 
					
						
							
								
									
										
										
										
											2009-02-19 00:26:01 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( iso  = =  SQL_TXN_READ_COMMITTED )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  " read_committed " ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									}  else  if  ( iso  = =  SQL_TXN_READ_UNCOMMITTED )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  " read_uncommitted " ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									}  else  if  ( iso  = =  SQL_TXN_SERIALIZABLE )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  " serializable " ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									}  else  if  ( iso  = =  SQL_TXN_REPEATABLE_READ )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  " repeatable_read " ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									}  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  " unknown " ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
											 
										
											
												res_odbc: Remove connection management
Asterisk by default will create a single database connection and share
it among all threads that attempt to access the database. In previous
versions of Asterisk, this was tolerable, because the most used channel
driver, chan_sip, mostly accessed the database from a single thread.
With PJSIP, however, many threads may be attempting to perform database
operations, and there is the potential for many more database accesses,
meaning the concurrency is a horrible bottleneck if only one connection
is shared.
Asterisk has a connection pooling facility built into it, but the
implementation has flaws. For one, there is a strict limit on the number
of simultaneous connections that could be made to the database. Anything
beyond the maximum would result in a failed operation. Attempting to
predict what the maximum should be is nearly impossible even for someone
intimately familiar with Asterisk's threading model. In addition, use of
transactions in the dialplan can cause some severe bugs if connection
pooling is enabled.
This commit seeks to fix the concurrency problem by removing all
connection management code from Asterisk and leaving that to the
underlying unixODBC code instead. Now, Asterisk does not share a single
connection, nor does it try to maintain a connection pool. Instead, all
Asterisk ever does is request a connection from unixODBC and allow
unixODBC to either allocate those connections or retrieve them from a
pool.
Doing this has a bit of a ripple effect. For one, since connections are
not long-lived objects, several of the safeguards that previously
existed have been removed. We don't have to worry about trying to use a
connection that has gone stale. In every case, when we request a
connection, it has just been made and we don't need to perform any
sanity checks to be sure it's still active.
Another major player affected by this change is transactions.
Transactions and their respective connections were so tightly coupled
that it was almost pornographic. This code change moves
transaction-related code to its own file separate from the core ODBC
functionality. This way, the core of ODBC does not even have to know
that transactions exist.
In making this large change, I had to look at a lot of code and
understand it. When making this change, I discovered several places
where the behavior is definitely not ideal, but it seemed outside the
scope of this change to be fixing it. Instead, any place where I saw
some sort of room for improvement has had a XXX comment added explaining
what could be altered to improve it.
Change-Id: I37a84def5ea4ddf93868ce8105f39de078297fbf
											 
										 
										
											2015-12-23 15:07:05 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								int  ast_odbc_text2isolation ( const  char  * txt )  
						 
					
						
							
								
									
										
										
										
											2009-02-19 00:26:01 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( strncasecmp ( txt ,  " read_ " ,  5 )  = =  0 )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ( strncasecmp ( txt  +  5 ,  " c " ,  1 )  = =  0 )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  SQL_TXN_READ_COMMITTED ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										}  else  if  ( strncasecmp ( txt  +  5 ,  " u " ,  1 )  = =  0 )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  SQL_TXN_READ_UNCOMMITTED ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										}  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									}  else  if  ( strncasecmp ( txt ,  " ser " ,  3 )  = =  0 )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  SQL_TXN_SERIALIZABLE ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									}  else  if  ( strncasecmp ( txt ,  " rep " ,  3 )  = =  0 )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  SQL_TXN_REPEATABLE_READ ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									}  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2008-05-05 23:38:15 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								static  void  odbc_class_destructor ( void  * data )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									struct  odbc_class  * class  =  data ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/* Due to refcounts, we can safely assume that any objects with a reference
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 *  to  us  will  prevent  our  destruction ,  so  we  don ' t  need  to  worry  about  them . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 */ 
							 
						 
					
						
							
								
									
										
										
										
											2009-02-19 00:26:01 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  ( class - > username )  { 
							 
						 
					
						
							
								
									
										
										
										
											2008-05-05 23:38:15 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										ast_free ( class - > username ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2009-02-19 00:26:01 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( class - > password )  { 
							 
						 
					
						
							
								
									
										
										
										
											2008-05-05 23:38:15 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										ast_free ( class - > password ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2009-02-19 00:26:01 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( class - > sanitysql )  { 
							 
						 
					
						
							
								
									
										
										
										
											2008-05-05 23:38:15 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										ast_free ( class - > sanitysql ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2009-02-19 00:26:01 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2008-05-05 23:38:15 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									SQLFreeHandle ( SQL_HANDLE_ENV ,  class - > env ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  int  null_hash_fn ( const  void  * obj ,  const  int  flags )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  void  odbc_obj_destructor ( void  * data )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									struct  odbc_obj  * obj  =  data ; 
							 
						 
					
						
							
								
									
										
										
										
											2009-02-17 18:49:20 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									struct  odbc_class  * class  =  obj - > parent ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									obj - > parent  =  NULL ; 
							 
						 
					
						
							
								
									
										
										
										
											2008-05-05 23:38:15 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									odbc_obj_disconnect ( obj ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2009-02-17 18:49:20 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									ao2_ref ( class ,  - 1 ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2008-05-05 23:38:15 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
									
										
										
										
											2004-06-11 00:12:35 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2008-06-10 21:14:58 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								static  void  destroy_table_cache ( struct  odbc_cache_tables  * table )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									struct  odbc_cache_columns  * col ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ast_debug ( 1 ,  " Destroying table cache for %s \n " ,  table - > table ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									AST_RWLIST_WRLOCK ( & table - > columns ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									while  ( ( col  =  AST_RWLIST_REMOVE_HEAD ( & table - > columns ,  list ) ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_free ( col ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									AST_RWLIST_UNLOCK ( & table - > columns ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									AST_RWLIST_HEAD_DESTROY ( & table - > columns ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ast_free ( table ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								/*!
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  \ brief  Find  or  create  an  entry  describing  the  table  specified . 
							 
						 
					
						
							
								
									
										
										
										
											2009-04-01 20:13:28 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								 *  \ param  database  Name  of  an  ODBC  class  on  which  to  query  the  table 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  \ param  tablename  Tablename  to  describe 
							 
						 
					
						
							
								
									
										
										
										
											2008-06-10 21:14:58 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								 *  \ retval  A  structure  describing  the  table  layout ,  or  NULL ,  if  the  table  is  not  found  or  another  error  occurs . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  When  a  structure  is  returned ,  the  contained  columns  list  will  be 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  rdlock ' ed ,  to  ensure  that  it  will  be  retained  in  memory . 
							 
						 
					
						
							
								
									
										
											 
										
											
												res_odbc: Remove connection management
Asterisk by default will create a single database connection and share
it among all threads that attempt to access the database. In previous
versions of Asterisk, this was tolerable, because the most used channel
driver, chan_sip, mostly accessed the database from a single thread.
With PJSIP, however, many threads may be attempting to perform database
operations, and there is the potential for many more database accesses,
meaning the concurrency is a horrible bottleneck if only one connection
is shared.
Asterisk has a connection pooling facility built into it, but the
implementation has flaws. For one, there is a strict limit on the number
of simultaneous connections that could be made to the database. Anything
beyond the maximum would result in a failed operation. Attempting to
predict what the maximum should be is nearly impossible even for someone
intimately familiar with Asterisk's threading model. In addition, use of
transactions in the dialplan can cause some severe bugs if connection
pooling is enabled.
This commit seeks to fix the concurrency problem by removing all
connection management code from Asterisk and leaving that to the
underlying unixODBC code instead. Now, Asterisk does not share a single
connection, nor does it try to maintain a connection pool. Instead, all
Asterisk ever does is request a connection from unixODBC and allow
unixODBC to either allocate those connections or retrieve them from a
pool.
Doing this has a bit of a ripple effect. For one, since connections are
not long-lived objects, several of the safeguards that previously
existed have been removed. We don't have to worry about trying to use a
connection that has gone stale. In every case, when we request a
connection, it has just been made and we don't need to perform any
sanity checks to be sure it's still active.
Another major player affected by this change is transactions.
Transactions and their respective connections were so tightly coupled
that it was almost pornographic. This code change moves
transaction-related code to its own file separate from the core ODBC
functionality. This way, the core of ODBC does not even have to know
that transactions exist.
In making this large change, I had to look at a lot of code and
understand it. When making this change, I discovered several places
where the behavior is definitely not ideal, but it seemed outside the
scope of this change to be fixing it. Instead, any place where I saw
some sort of room for improvement has had a XXX comment added explaining
what could be altered to improve it.
Change-Id: I37a84def5ea4ddf93868ce8105f39de078297fbf
											 
										 
										
											2015-12-23 15:07:05 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								 * 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  XXX  This  creates  a  connection  and  disconnects  it .  In  some  situations ,  the  caller  of 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  this  function  has  its  own  connection  and  could  donate  it  to  this  function  instead  of 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  needing  to  create  another  one . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 * 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  XXX  The  automatic  readlock  of  the  columns  is  awkward .  It ' s  done  because  it ' s  possible  for 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  multiple  threads  to  have  references  to  the  table ,  and  the  table  is  not  refcounted .  Possible 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  changes  here  would  be 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  *  Eliminate  the  table  cache  entirely .  The  use  of  ast_odbc_find_table ( )  is  generally 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *    questionable .  The  only  real  good  use  right  now  is  from  ast_realtime_require_field ( )  in 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *    order  to  make  sure  the  DB  has  the  expected  columns  in  it .  Since  that  is  only  used  sparingly , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *    the  need  to  cache  tables  is  questionable .  Instead ,  the  table  structure  can  be  fetched  from 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *    the  DB  directly  each  time ,  resulting  in  a  single  owner  of  the  data . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  *  Make  odbc_cache_tables  a  refcounted  object . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 * 
							 
						 
					
						
							
								
									
										
										
										
											2009-04-01 20:13:28 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								 *  \ since  1.6 .1 
							 
						 
					
						
							
								
									
										
										
										
											2008-06-10 21:14:58 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								 */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								struct  odbc_cache_tables  * ast_odbc_find_table ( const  char  * database ,  const  char  * tablename )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									struct  odbc_cache_tables  * tableptr ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									struct  odbc_cache_columns  * entry ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									char  columnname [ 80 ] ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									SQLLEN  sqlptr ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									SQLHSTMT  stmt  =  NULL ; 
							 
						 
					
						
							
								
									
										
											 
										
											
												res_odbc: Remove connection management
Asterisk by default will create a single database connection and share
it among all threads that attempt to access the database. In previous
versions of Asterisk, this was tolerable, because the most used channel
driver, chan_sip, mostly accessed the database from a single thread.
With PJSIP, however, many threads may be attempting to perform database
operations, and there is the potential for many more database accesses,
meaning the concurrency is a horrible bottleneck if only one connection
is shared.
Asterisk has a connection pooling facility built into it, but the
implementation has flaws. For one, there is a strict limit on the number
of simultaneous connections that could be made to the database. Anything
beyond the maximum would result in a failed operation. Attempting to
predict what the maximum should be is nearly impossible even for someone
intimately familiar with Asterisk's threading model. In addition, use of
transactions in the dialplan can cause some severe bugs if connection
pooling is enabled.
This commit seeks to fix the concurrency problem by removing all
connection management code from Asterisk and leaving that to the
underlying unixODBC code instead. Now, Asterisk does not share a single
connection, nor does it try to maintain a connection pool. Instead, all
Asterisk ever does is request a connection from unixODBC and allow
unixODBC to either allocate those connections or retrieve them from a
pool.
Doing this has a bit of a ripple effect. For one, since connections are
not long-lived objects, several of the safeguards that previously
existed have been removed. We don't have to worry about trying to use a
connection that has gone stale. In every case, when we request a
connection, it has just been made and we don't need to perform any
sanity checks to be sure it's still active.
Another major player affected by this change is transactions.
Transactions and their respective connections were so tightly coupled
that it was almost pornographic. This code change moves
transaction-related code to its own file separate from the core ODBC
functionality. This way, the core of ODBC does not even have to know
that transactions exist.
In making this large change, I had to look at a lot of code and
understand it. When making this change, I discovered several places
where the behavior is definitely not ideal, but it seemed outside the
scope of this change to be fixing it. Instead, any place where I saw
some sort of room for improvement has had a XXX comment added explaining
what could be altered to improve it.
Change-Id: I37a84def5ea4ddf93868ce8105f39de078297fbf
											 
										 
										
											2015-12-23 15:07:05 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									int  res  =  0 ,  error  =  0 ; 
							 
						 
					
						
							
								
									
										
										
										
											2015-02-09 02:35:31 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									struct  odbc_obj  * obj ; 
							 
						 
					
						
							
								
									
										
										
										
											2008-06-10 21:14:58 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									AST_RWLIST_RDLOCK ( & odbc_tables ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									AST_RWLIST_TRAVERSE ( & odbc_tables ,  tableptr ,  list )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ( strcmp ( tableptr - > connection ,  database )  = =  0  & &  strcmp ( tableptr - > table ,  tablename )  = =  0 )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											break ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( tableptr )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										AST_RWLIST_RDLOCK ( & tableptr - > columns ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										AST_RWLIST_UNLOCK ( & odbc_tables ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  tableptr ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2015-02-09 02:35:31 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  ( ! ( obj  =  ast_odbc_request_obj ( database ,  0 ) ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2008-06-10 21:14:58 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										ast_log ( LOG_WARNING ,  " Unable to retrieve database handle for table description '%s@%s' \n " ,  tablename ,  database ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2009-02-19 00:26:01 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										AST_RWLIST_UNLOCK ( & odbc_tables ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2008-06-10 21:14:58 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										return  NULL ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/* Table structure not already cached; build it now. */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									do  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										res  =  SQLAllocHandle ( SQL_HANDLE_STMT ,  obj - > con ,  & stmt ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ( ( res  ! =  SQL_SUCCESS )  & &  ( res  ! =  SQL_SUCCESS_WITH_INFO ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ast_log ( LOG_WARNING ,  " SQL Alloc Handle failed on connection '%s'! \n " ,  database ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											break ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										res  =  SQLColumns ( stmt ,  NULL ,  0 ,  NULL ,  0 ,  ( unsigned  char  * ) tablename ,  SQL_NTS ,  ( unsigned  char  * ) " % " ,  SQL_NTS ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ( ( res  ! =  SQL_SUCCESS )  & &  ( res  ! =  SQL_SUCCESS_WITH_INFO ) )  { 
							 
						 
					
						
							
								
									
										
											 
										
											
												res_odbc: Remove connection management
Asterisk by default will create a single database connection and share
it among all threads that attempt to access the database. In previous
versions of Asterisk, this was tolerable, because the most used channel
driver, chan_sip, mostly accessed the database from a single thread.
With PJSIP, however, many threads may be attempting to perform database
operations, and there is the potential for many more database accesses,
meaning the concurrency is a horrible bottleneck if only one connection
is shared.
Asterisk has a connection pooling facility built into it, but the
implementation has flaws. For one, there is a strict limit on the number
of simultaneous connections that could be made to the database. Anything
beyond the maximum would result in a failed operation. Attempting to
predict what the maximum should be is nearly impossible even for someone
intimately familiar with Asterisk's threading model. In addition, use of
transactions in the dialplan can cause some severe bugs if connection
pooling is enabled.
This commit seeks to fix the concurrency problem by removing all
connection management code from Asterisk and leaving that to the
underlying unixODBC code instead. Now, Asterisk does not share a single
connection, nor does it try to maintain a connection pool. Instead, all
Asterisk ever does is request a connection from unixODBC and allow
unixODBC to either allocate those connections or retrieve them from a
pool.
Doing this has a bit of a ripple effect. For one, since connections are
not long-lived objects, several of the safeguards that previously
existed have been removed. We don't have to worry about trying to use a
connection that has gone stale. In every case, when we request a
connection, it has just been made and we don't need to perform any
sanity checks to be sure it's still active.
Another major player affected by this change is transactions.
Transactions and their respective connections were so tightly coupled
that it was almost pornographic. This code change moves
transaction-related code to its own file separate from the core ODBC
functionality. This way, the core of ODBC does not even have to know
that transactions exist.
In making this large change, I had to look at a lot of code and
understand it. When making this change, I discovered several places
where the behavior is definitely not ideal, but it seemed outside the
scope of this change to be fixing it. Instead, any place where I saw
some sort of room for improvement has had a XXX comment added explaining
what could be altered to improve it.
Change-Id: I37a84def5ea4ddf93868ce8105f39de078297fbf
											 
										 
										
											2015-12-23 15:07:05 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											SQLFreeHandle ( SQL_HANDLE_STMT ,  stmt ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2008-06-10 21:14:58 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											ast_log ( LOG_ERROR ,  " Unable to query database columns on connection '%s'. \n " ,  database ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											break ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ( ! ( tableptr  =  ast_calloc ( sizeof ( char ) ,  sizeof ( * tableptr )  +  strlen ( database )  +  1  +  strlen ( tablename )  +  1 ) ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ast_log ( LOG_ERROR ,  " Out of memory creating entry for table '%s' on connection '%s' \n " ,  tablename ,  database ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											break ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										tableptr - > connection  =  ( char  * ) tableptr  +  sizeof ( * tableptr ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										tableptr - > table  =  ( char  * ) tableptr  +  sizeof ( * tableptr )  +  strlen ( database )  +  1 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										strcpy ( tableptr - > connection ,  database ) ;  /* SAFE */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										strcpy ( tableptr - > table ,  tablename ) ;  /* SAFE */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										AST_RWLIST_HEAD_INIT ( & ( tableptr - > columns ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										while  ( ( res  =  SQLFetch ( stmt ) )  ! =  SQL_NO_DATA  & &  res  ! =  SQL_ERROR )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											SQLGetData ( stmt ,   4 ,  SQL_C_CHAR ,  columnname ,  sizeof ( columnname ) ,  & sqlptr ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  ( ! ( entry  =  ast_calloc ( sizeof ( char ) ,  sizeof ( * entry )  +  strlen ( columnname )  +  1 ) ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												ast_log ( LOG_ERROR ,  " Out of memory creating entry for column '%s' in table '%s' on connection '%s' \n " ,  columnname ,  tablename ,  database ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												error  =  1 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												break ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											entry - > name  =  ( char  * ) entry  +  sizeof ( * entry ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											strcpy ( entry - > name ,  columnname ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											SQLGetData ( stmt ,   5 ,  SQL_C_SHORT ,  & entry - > type ,  sizeof ( entry - > type ) ,  NULL ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											SQLGetData ( stmt ,   7 ,  SQL_C_LONG ,  & entry - > size ,  sizeof ( entry - > size ) ,  NULL ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											SQLGetData ( stmt ,   9 ,  SQL_C_SHORT ,  & entry - > decimals ,  sizeof ( entry - > decimals ) ,  NULL ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											SQLGetData ( stmt ,  10 ,  SQL_C_SHORT ,  & entry - > radix ,  sizeof ( entry - > radix ) ,  NULL ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											SQLGetData ( stmt ,  11 ,  SQL_C_SHORT ,  & entry - > nullable ,  sizeof ( entry - > nullable ) ,  NULL ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											SQLGetData ( stmt ,  16 ,  SQL_C_LONG ,  & entry - > octetlen ,  sizeof ( entry - > octetlen ) ,  NULL ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											/* Specification states that the octenlen should be the maximum number of bytes
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											 *  returned  in  a  char  or  binary  column ,  but  it  seems  that  some  drivers  just  set 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											 *  it  to  NULL .  ( Bad  Postgres !  No  biscuit ! )  */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  ( entry - > octetlen  = =  0 )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												entry - > octetlen  =  entry - > size ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-05-28 22:54:12 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											ast_debug ( 3 ,  " Found %s column with type %hd with len %ld, octetlen %ld, and numlen (%hd,%hd) \n " ,  entry - > name ,  entry - > type ,  ( long )  entry - > size ,  ( long )  entry - > octetlen ,  entry - > decimals ,  entry - > radix ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2008-06-10 21:14:58 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											/* Insert column info into column list */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											AST_LIST_INSERT_TAIL ( & ( tableptr - > columns ) ,  entry ,  list ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										SQLFreeHandle ( SQL_HANDLE_STMT ,  stmt ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										AST_RWLIST_INSERT_TAIL ( & odbc_tables ,  tableptr ,  list ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										AST_RWLIST_RDLOCK ( & ( tableptr - > columns ) ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2009-02-19 00:26:01 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										break ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									}  while  ( 1 ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2008-06-10 21:14:58 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									AST_RWLIST_UNLOCK ( & odbc_tables ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( error )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										destroy_table_cache ( tableptr ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										tableptr  =  NULL ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2015-02-09 02:35:31 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									ast_odbc_release_obj ( obj ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2008-06-10 21:14:58 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									return  tableptr ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								struct  odbc_cache_columns  * ast_odbc_find_column ( struct  odbc_cache_tables  * table ,  const  char  * colname )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									struct  odbc_cache_columns  * col ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									AST_RWLIST_TRAVERSE ( & table - > columns ,  col ,  list )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ( strcasecmp ( col - > name ,  colname )  = =  0 )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  col ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  NULL ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								int  ast_odbc_clear_cache ( const  char  * database ,  const  char  * tablename )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									struct  odbc_cache_tables  * tableptr ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									AST_RWLIST_WRLOCK ( & odbc_tables ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									AST_RWLIST_TRAVERSE_SAFE_BEGIN ( & odbc_tables ,  tableptr ,  list )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ( strcmp ( tableptr - > connection ,  database )  = =  0  & &  strcmp ( tableptr - > table ,  tablename )  = =  0 )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											AST_LIST_REMOVE_CURRENT ( list ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											destroy_table_cache ( tableptr ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											break ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									AST_RWLIST_TRAVERSE_SAFE_END 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									AST_RWLIST_UNLOCK ( & odbc_tables ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  tableptr  ?  0  :  - 1 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2007-09-14 17:29:23 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								SQLHSTMT  ast_odbc_direct_execute ( struct  odbc_obj  * obj ,  SQLHSTMT  ( * exec_cb ) ( struct  odbc_obj  * obj ,  void  * data ) ,  void  * data )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									SQLHSTMT  stmt ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
											 
										
											
												res_odbc: Remove connection management
Asterisk by default will create a single database connection and share
it among all threads that attempt to access the database. In previous
versions of Asterisk, this was tolerable, because the most used channel
driver, chan_sip, mostly accessed the database from a single thread.
With PJSIP, however, many threads may be attempting to perform database
operations, and there is the potential for many more database accesses,
meaning the concurrency is a horrible bottleneck if only one connection
is shared.
Asterisk has a connection pooling facility built into it, but the
implementation has flaws. For one, there is a strict limit on the number
of simultaneous connections that could be made to the database. Anything
beyond the maximum would result in a failed operation. Attempting to
predict what the maximum should be is nearly impossible even for someone
intimately familiar with Asterisk's threading model. In addition, use of
transactions in the dialplan can cause some severe bugs if connection
pooling is enabled.
This commit seeks to fix the concurrency problem by removing all
connection management code from Asterisk and leaving that to the
underlying unixODBC code instead. Now, Asterisk does not share a single
connection, nor does it try to maintain a connection pool. Instead, all
Asterisk ever does is request a connection from unixODBC and allow
unixODBC to either allocate those connections or retrieve them from a
pool.
Doing this has a bit of a ripple effect. For one, since connections are
not long-lived objects, several of the safeguards that previously
existed have been removed. We don't have to worry about trying to use a
connection that has gone stale. In every case, when we request a
connection, it has just been made and we don't need to perform any
sanity checks to be sure it's still active.
Another major player affected by this change is transactions.
Transactions and their respective connections were so tightly coupled
that it was almost pornographic. This code change moves
transaction-related code to its own file separate from the core ODBC
functionality. This way, the core of ODBC does not even have to know
that transactions exist.
In making this large change, I had to look at a lot of code and
understand it. When making this change, I discovered several places
where the behavior is definitely not ideal, but it seemed outside the
scope of this change to be fixing it. Instead, any place where I saw
some sort of room for improvement has had a XXX comment added explaining
what could be altered to improve it.
Change-Id: I37a84def5ea4ddf93868ce8105f39de078297fbf
											 
										 
										
											2015-12-23 15:07:05 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									stmt  =  exec_cb ( obj ,  data ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2012-02-27 15:35:10 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2007-09-14 17:29:23 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									return  stmt ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2006-09-20 04:57:20 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								SQLHSTMT  ast_odbc_prepare_and_execute ( struct  odbc_obj  * obj ,  SQLHSTMT  ( * prepare_cb ) ( struct  odbc_obj  * obj ,  void  * data ) ,  void  * data )  
						 
					
						
							
								
									
										
										
										
											2005-11-09 02:01:12 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
									
										
											 
										
											
												res_odbc: Remove connection management
Asterisk by default will create a single database connection and share
it among all threads that attempt to access the database. In previous
versions of Asterisk, this was tolerable, because the most used channel
driver, chan_sip, mostly accessed the database from a single thread.
With PJSIP, however, many threads may be attempting to perform database
operations, and there is the potential for many more database accesses,
meaning the concurrency is a horrible bottleneck if only one connection
is shared.
Asterisk has a connection pooling facility built into it, but the
implementation has flaws. For one, there is a strict limit on the number
of simultaneous connections that could be made to the database. Anything
beyond the maximum would result in a failed operation. Attempting to
predict what the maximum should be is nearly impossible even for someone
intimately familiar with Asterisk's threading model. In addition, use of
transactions in the dialplan can cause some severe bugs if connection
pooling is enabled.
This commit seeks to fix the concurrency problem by removing all
connection management code from Asterisk and leaving that to the
underlying unixODBC code instead. Now, Asterisk does not share a single
connection, nor does it try to maintain a connection pool. Instead, all
Asterisk ever does is request a connection from unixODBC and allow
unixODBC to either allocate those connections or retrieve them from a
pool.
Doing this has a bit of a ripple effect. For one, since connections are
not long-lived objects, several of the safeguards that previously
existed have been removed. We don't have to worry about trying to use a
connection that has gone stale. In every case, when we request a
connection, it has just been made and we don't need to perform any
sanity checks to be sure it's still active.
Another major player affected by this change is transactions.
Transactions and their respective connections were so tightly coupled
that it was almost pornographic. This code change moves
transaction-related code to its own file separate from the core ODBC
functionality. This way, the core of ODBC does not even have to know
that transactions exist.
In making this large change, I had to look at a lot of code and
understand it. When making this change, I discovered several places
where the behavior is definitely not ideal, but it seemed outside the
scope of this change to be fixing it. Instead, any place where I saw
some sort of room for improvement has had a XXX comment added explaining
what could be altered to improve it.
Change-Id: I37a84def5ea4ddf93868ce8105f39de078297fbf
											 
										 
										
											2015-12-23 15:07:05 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									int  res  =  0 ; 
							 
						 
					
						
							
								
									
										
										
										
											2005-11-09 02:01:12 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									SQLHSTMT  stmt ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
											 
										
											
												res_odbc: Remove connection management
Asterisk by default will create a single database connection and share
it among all threads that attempt to access the database. In previous
versions of Asterisk, this was tolerable, because the most used channel
driver, chan_sip, mostly accessed the database from a single thread.
With PJSIP, however, many threads may be attempting to perform database
operations, and there is the potential for many more database accesses,
meaning the concurrency is a horrible bottleneck if only one connection
is shared.
Asterisk has a connection pooling facility built into it, but the
implementation has flaws. For one, there is a strict limit on the number
of simultaneous connections that could be made to the database. Anything
beyond the maximum would result in a failed operation. Attempting to
predict what the maximum should be is nearly impossible even for someone
intimately familiar with Asterisk's threading model. In addition, use of
transactions in the dialplan can cause some severe bugs if connection
pooling is enabled.
This commit seeks to fix the concurrency problem by removing all
connection management code from Asterisk and leaving that to the
underlying unixODBC code instead. Now, Asterisk does not share a single
connection, nor does it try to maintain a connection pool. Instead, all
Asterisk ever does is request a connection from unixODBC and allow
unixODBC to either allocate those connections or retrieve them from a
pool.
Doing this has a bit of a ripple effect. For one, since connections are
not long-lived objects, several of the safeguards that previously
existed have been removed. We don't have to worry about trying to use a
connection that has gone stale. In every case, when we request a
connection, it has just been made and we don't need to perform any
sanity checks to be sure it's still active.
Another major player affected by this change is transactions.
Transactions and their respective connections were so tightly coupled
that it was almost pornographic. This code change moves
transaction-related code to its own file separate from the core ODBC
functionality. This way, the core of ODBC does not even have to know
that transactions exist.
In making this large change, I had to look at a lot of code and
understand it. When making this change, I discovered several places
where the behavior is definitely not ideal, but it seemed outside the
scope of this change to be fixing it. Instead, any place where I saw
some sort of room for improvement has had a XXX comment added explaining
what could be altered to improve it.
Change-Id: I37a84def5ea4ddf93868ce8105f39de078297fbf
											 
										 
										
											2015-12-23 15:07:05 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									/* This prepare callback may do more than just prepare -- it may also
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 *  bind  parameters ,  bind  results ,  etc .   The  real  key ,  here ,  is  that 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 *  when  we  disconnect ,  all  handles  become  invalid  for  most  databases . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 *  We  must  therefore  redo  everything  when  we  establish  a  new 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 *  connection .  */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									stmt  =  prepare_cb ( obj ,  data ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2005-11-09 02:01:12 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
											 
										
											
												res_odbc: Remove connection management
Asterisk by default will create a single database connection and share
it among all threads that attempt to access the database. In previous
versions of Asterisk, this was tolerable, because the most used channel
driver, chan_sip, mostly accessed the database from a single thread.
With PJSIP, however, many threads may be attempting to perform database
operations, and there is the potential for many more database accesses,
meaning the concurrency is a horrible bottleneck if only one connection
is shared.
Asterisk has a connection pooling facility built into it, but the
implementation has flaws. For one, there is a strict limit on the number
of simultaneous connections that could be made to the database. Anything
beyond the maximum would result in a failed operation. Attempting to
predict what the maximum should be is nearly impossible even for someone
intimately familiar with Asterisk's threading model. In addition, use of
transactions in the dialplan can cause some severe bugs if connection
pooling is enabled.
This commit seeks to fix the concurrency problem by removing all
connection management code from Asterisk and leaving that to the
underlying unixODBC code instead. Now, Asterisk does not share a single
connection, nor does it try to maintain a connection pool. Instead, all
Asterisk ever does is request a connection from unixODBC and allow
unixODBC to either allocate those connections or retrieve them from a
pool.
Doing this has a bit of a ripple effect. For one, since connections are
not long-lived objects, several of the safeguards that previously
existed have been removed. We don't have to worry about trying to use a
connection that has gone stale. In every case, when we request a
connection, it has just been made and we don't need to perform any
sanity checks to be sure it's still active.
Another major player affected by this change is transactions.
Transactions and their respective connections were so tightly coupled
that it was almost pornographic. This code change moves
transaction-related code to its own file separate from the core ODBC
functionality. This way, the core of ODBC does not even have to know
that transactions exist.
In making this large change, I had to look at a lot of code and
understand it. When making this change, I discovered several places
where the behavior is definitely not ideal, but it seemed outside the
scope of this change to be fixing it. Instead, any place where I saw
some sort of room for improvement has had a XXX comment added explaining
what could be altered to improve it.
Change-Id: I37a84def5ea4ddf93868ce8105f39de078297fbf
											 
										 
										
											2015-12-23 15:07:05 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  ( stmt )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										res  =  SQLExecute ( stmt ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ( ( res  ! =  SQL_SUCCESS )  & &  ( res  ! =  SQL_SUCCESS_WITH_INFO )  & &  ( res  ! =  SQL_NO_DATA ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  ( res  = =  SQL_ERROR )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												ast_odbc_print_errors ( SQL_HANDLE_STMT ,  stmt ,  " SQL Execute " ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2009-02-19 00:26:01 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
									
										
											 
										
											
												res_odbc: Remove connection management
Asterisk by default will create a single database connection and share
it among all threads that attempt to access the database. In previous
versions of Asterisk, this was tolerable, because the most used channel
driver, chan_sip, mostly accessed the database from a single thread.
With PJSIP, however, many threads may be attempting to perform database
operations, and there is the potential for many more database accesses,
meaning the concurrency is a horrible bottleneck if only one connection
is shared.
Asterisk has a connection pooling facility built into it, but the
implementation has flaws. For one, there is a strict limit on the number
of simultaneous connections that could be made to the database. Anything
beyond the maximum would result in a failed operation. Attempting to
predict what the maximum should be is nearly impossible even for someone
intimately familiar with Asterisk's threading model. In addition, use of
transactions in the dialplan can cause some severe bugs if connection
pooling is enabled.
This commit seeks to fix the concurrency problem by removing all
connection management code from Asterisk and leaving that to the
underlying unixODBC code instead. Now, Asterisk does not share a single
connection, nor does it try to maintain a connection pool. Instead, all
Asterisk ever does is request a connection from unixODBC and allow
unixODBC to either allocate those connections or retrieve them from a
pool.
Doing this has a bit of a ripple effect. For one, since connections are
not long-lived objects, several of the safeguards that previously
existed have been removed. We don't have to worry about trying to use a
connection that has gone stale. In every case, when we request a
connection, it has just been made and we don't need to perform any
sanity checks to be sure it's still active.
Another major player affected by this change is transactions.
Transactions and their respective connections were so tightly coupled
that it was almost pornographic. This code change moves
transaction-related code to its own file separate from the core ODBC
functionality. This way, the core of ODBC does not even have to know
that transactions exist.
In making this large change, I had to look at a lot of code and
understand it. When making this change, I discovered several places
where the behavior is definitely not ideal, but it seemed outside the
scope of this change to be fixing it. Instead, any place where I saw
some sort of room for improvement has had a XXX comment added explaining
what could be altered to improve it.
Change-Id: I37a84def5ea4ddf93868ce8105f39de078297fbf
											 
										 
										
											2015-12-23 15:07:05 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ast_log ( LOG_WARNING ,  " SQL Execute error %d! \n " ,  res ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											SQLFreeHandle ( SQL_HANDLE_STMT ,  stmt ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											stmt  =  NULL ; 
							 
						 
					
						
							
								
									
										
										
										
											2009-02-19 00:26:01 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2005-11-09 02:01:12 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  stmt ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2010-07-23 16:19:21 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								int  ast_odbc_smart_execute ( struct  odbc_obj  * obj ,  SQLHSTMT  stmt )  
						 
					
						
							
								
									
										
										
										
											2005-02-17 16:31:08 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
									
										
											 
										
											
												res_odbc: Remove connection management
Asterisk by default will create a single database connection and share
it among all threads that attempt to access the database. In previous
versions of Asterisk, this was tolerable, because the most used channel
driver, chan_sip, mostly accessed the database from a single thread.
With PJSIP, however, many threads may be attempting to perform database
operations, and there is the potential for many more database accesses,
meaning the concurrency is a horrible bottleneck if only one connection
is shared.
Asterisk has a connection pooling facility built into it, but the
implementation has flaws. For one, there is a strict limit on the number
of simultaneous connections that could be made to the database. Anything
beyond the maximum would result in a failed operation. Attempting to
predict what the maximum should be is nearly impossible even for someone
intimately familiar with Asterisk's threading model. In addition, use of
transactions in the dialplan can cause some severe bugs if connection
pooling is enabled.
This commit seeks to fix the concurrency problem by removing all
connection management code from Asterisk and leaving that to the
underlying unixODBC code instead. Now, Asterisk does not share a single
connection, nor does it try to maintain a connection pool. Instead, all
Asterisk ever does is request a connection from unixODBC and allow
unixODBC to either allocate those connections or retrieve them from a
pool.
Doing this has a bit of a ripple effect. For one, since connections are
not long-lived objects, several of the safeguards that previously
existed have been removed. We don't have to worry about trying to use a
connection that has gone stale. In every case, when we request a
connection, it has just been made and we don't need to perform any
sanity checks to be sure it's still active.
Another major player affected by this change is transactions.
Transactions and their respective connections were so tightly coupled
that it was almost pornographic. This code change moves
transaction-related code to its own file separate from the core ODBC
functionality. This way, the core of ODBC does not even have to know
that transactions exist.
In making this large change, I had to look at a lot of code and
understand it. When making this change, I discovered several places
where the behavior is definitely not ideal, but it seemed outside the
scope of this change to be fixing it. Instead, any place where I saw
some sort of room for improvement has had a XXX comment added explaining
what could be altered to improve it.
Change-Id: I37a84def5ea4ddf93868ce8105f39de078297fbf
											 
										 
										
											2015-12-23 15:07:05 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									int  res  =  0 ; 
							 
						 
					
						
							
								
									
										
										
										
											2012-02-27 15:35:10 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2005-02-17 16:31:08 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									res  =  SQLExecute ( stmt ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2005-10-31 21:31:25 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  ( ( res  ! =  SQL_SUCCESS )  & &  ( res  ! =  SQL_SUCCESS_WITH_INFO )  & &  ( res  ! =  SQL_NO_DATA ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2005-11-09 02:01:12 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  ( res  = =  SQL_ERROR )  { 
							 
						 
					
						
							
								
									
										
											 
										
											
												res_odbc: Remove connection management
Asterisk by default will create a single database connection and share
it among all threads that attempt to access the database. In previous
versions of Asterisk, this was tolerable, because the most used channel
driver, chan_sip, mostly accessed the database from a single thread.
With PJSIP, however, many threads may be attempting to perform database
operations, and there is the potential for many more database accesses,
meaning the concurrency is a horrible bottleneck if only one connection
is shared.
Asterisk has a connection pooling facility built into it, but the
implementation has flaws. For one, there is a strict limit on the number
of simultaneous connections that could be made to the database. Anything
beyond the maximum would result in a failed operation. Attempting to
predict what the maximum should be is nearly impossible even for someone
intimately familiar with Asterisk's threading model. In addition, use of
transactions in the dialplan can cause some severe bugs if connection
pooling is enabled.
This commit seeks to fix the concurrency problem by removing all
connection management code from Asterisk and leaving that to the
underlying unixODBC code instead. Now, Asterisk does not share a single
connection, nor does it try to maintain a connection pool. Instead, all
Asterisk ever does is request a connection from unixODBC and allow
unixODBC to either allocate those connections or retrieve them from a
pool.
Doing this has a bit of a ripple effect. For one, since connections are
not long-lived objects, several of the safeguards that previously
existed have been removed. We don't have to worry about trying to use a
connection that has gone stale. In every case, when we request a
connection, it has just been made and we don't need to perform any
sanity checks to be sure it's still active.
Another major player affected by this change is transactions.
Transactions and their respective connections were so tightly coupled
that it was almost pornographic. This code change moves
transaction-related code to its own file separate from the core ODBC
functionality. This way, the core of ODBC does not even have to know
that transactions exist.
In making this large change, I had to look at a lot of code and
understand it. When making this change, I discovered several places
where the behavior is definitely not ideal, but it seemed outside the
scope of this change to be fixing it. Instead, any place where I saw
some sort of room for improvement has had a XXX comment added explaining
what could be altered to improve it.
Change-Id: I37a84def5ea4ddf93868ce8105f39de078297fbf
											 
										 
										
											2015-12-23 15:07:05 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											ast_odbc_print_errors ( SQL_HANDLE_STMT ,  stmt ,  " SQL Execute " ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2005-11-09 02:01:12 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2010-07-23 16:19:21 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2005-02-17 16:31:08 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									return  res ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2009-01-19 21:42:46 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								SQLRETURN  ast_odbc_ast_str_SQLGetData ( struct  ast_str  * * buf ,  int  pmaxlen ,  SQLHSTMT  StatementHandle ,  SQLUSMALLINT  ColumnNumber ,  SQLSMALLINT  TargetType ,  SQLLEN  * StrLen_or_Ind )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									SQLRETURN  res ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( pmaxlen  = =  0 )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ( SQLGetData ( StatementHandle ,  ColumnNumber ,  TargetType ,  ast_str_buffer ( * buf ) ,  0 ,  StrLen_or_Ind )  = =  SQL_SUCCESS_WITH_INFO )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ast_str_make_space ( buf ,  * StrLen_or_Ind  +  1 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									}  else  if  ( pmaxlen  >  0 )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_str_make_space ( buf ,  pmaxlen ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									res  =  SQLGetData ( StatementHandle ,  ColumnNumber ,  TargetType ,  ast_str_buffer ( * buf ) ,  ast_str_size ( * buf ) ,  StrLen_or_Ind ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ast_str_update ( * buf ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  res ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
									
										
										
										
											2005-02-17 16:31:08 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
											 
										
											
												res_odbc: Remove connection management
Asterisk by default will create a single database connection and share
it among all threads that attempt to access the database. In previous
versions of Asterisk, this was tolerable, because the most used channel
driver, chan_sip, mostly accessed the database from a single thread.
With PJSIP, however, many threads may be attempting to perform database
operations, and there is the potential for many more database accesses,
meaning the concurrency is a horrible bottleneck if only one connection
is shared.
Asterisk has a connection pooling facility built into it, but the
implementation has flaws. For one, there is a strict limit on the number
of simultaneous connections that could be made to the database. Anything
beyond the maximum would result in a failed operation. Attempting to
predict what the maximum should be is nearly impossible even for someone
intimately familiar with Asterisk's threading model. In addition, use of
transactions in the dialplan can cause some severe bugs if connection
pooling is enabled.
This commit seeks to fix the concurrency problem by removing all
connection management code from Asterisk and leaving that to the
underlying unixODBC code instead. Now, Asterisk does not share a single
connection, nor does it try to maintain a connection pool. Instead, all
Asterisk ever does is request a connection from unixODBC and allow
unixODBC to either allocate those connections or retrieve them from a
pool.
Doing this has a bit of a ripple effect. For one, since connections are
not long-lived objects, several of the safeguards that previously
existed have been removed. We don't have to worry about trying to use a
connection that has gone stale. In every case, when we request a
connection, it has just been made and we don't need to perform any
sanity checks to be sure it's still active.
Another major player affected by this change is transactions.
Transactions and their respective connections were so tightly coupled
that it was almost pornographic. This code change moves
transaction-related code to its own file separate from the core ODBC
functionality. This way, the core of ODBC does not even have to know
that transactions exist.
In making this large change, I had to look at a lot of code and
understand it. When making this change, I discovered several places
where the behavior is definitely not ideal, but it seemed outside the
scope of this change to be fixing it. Instead, any place where I saw
some sort of room for improvement has had a XXX comment added explaining
what could be altered to improve it.
Change-Id: I37a84def5ea4ddf93868ce8105f39de078297fbf
											 
										 
										
											2015-12-23 15:07:05 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								struct  ast_str  * ast_odbc_print_errors ( SQLSMALLINT  handle_type ,  SQLHANDLE  handle ,  const  char  * operation )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									struct  ast_str  * errors  =  ast_str_thread_get ( & errors_buf ,  16 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									SQLINTEGER  nativeerror  =  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									SQLINTEGER  numfields  =  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									SQLSMALLINT  diagbytes  =  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									SQLSMALLINT  i ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									unsigned  char  state [ 10 ] ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									unsigned  char  diagnostic [ 256 ] ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ast_str_reset ( errors ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									SQLGetDiagField ( handle_type ,  handle ,  1 ,  SQL_DIAG_NUMBER ,  & numfields , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											SQL_IS_INTEGER ,  & diagbytes ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									for  ( i  =  0 ;  i  <  numfields ;  i + + )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										SQLGetDiagRec ( handle_type ,  handle ,  i  +  1 ,  state ,  & nativeerror , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												diagnostic ,  sizeof ( diagnostic ) ,  & diagbytes ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_str_append ( & errors ,  0 ,  " %s%s " ,  ast_str_strlen ( errors )  ?  " , "  :  " " ,  state ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_log ( LOG_WARNING ,  " %s returned an error: %s: %s \n " ,  operation ,  state ,  diagnostic ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										/* XXX Why is this here? */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ( i  >  10 )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ast_log ( LOG_WARNING ,  " Oh, that was good.  There are really %d diagnostics? \n " ,  ( int ) numfields ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											break ; 
							 
						 
					
						
							
								
									
										
										
										
											2005-02-17 16:31:08 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
											 
										
											
												res_odbc: Remove connection management
Asterisk by default will create a single database connection and share
it among all threads that attempt to access the database. In previous
versions of Asterisk, this was tolerable, because the most used channel
driver, chan_sip, mostly accessed the database from a single thread.
With PJSIP, however, many threads may be attempting to perform database
operations, and there is the potential for many more database accesses,
meaning the concurrency is a horrible bottleneck if only one connection
is shared.
Asterisk has a connection pooling facility built into it, but the
implementation has flaws. For one, there is a strict limit on the number
of simultaneous connections that could be made to the database. Anything
beyond the maximum would result in a failed operation. Attempting to
predict what the maximum should be is nearly impossible even for someone
intimately familiar with Asterisk's threading model. In addition, use of
transactions in the dialplan can cause some severe bugs if connection
pooling is enabled.
This commit seeks to fix the concurrency problem by removing all
connection management code from Asterisk and leaving that to the
underlying unixODBC code instead. Now, Asterisk does not share a single
connection, nor does it try to maintain a connection pool. Instead, all
Asterisk ever does is request a connection from unixODBC and allow
unixODBC to either allocate those connections or retrieve them from a
pool.
Doing this has a bit of a ripple effect. For one, since connections are
not long-lived objects, several of the safeguards that previously
existed have been removed. We don't have to worry about trying to use a
connection that has gone stale. In every case, when we request a
connection, it has just been made and we don't need to perform any
sanity checks to be sure it's still active.
Another major player affected by this change is transactions.
Transactions and their respective connections were so tightly coupled
that it was almost pornographic. This code change moves
transaction-related code to its own file separate from the core ODBC
functionality. This way, the core of ODBC does not even have to know
that transactions exist.
In making this large change, I had to look at a lot of code and
understand it. When making this change, I discovered several places
where the behavior is definitely not ideal, but it seemed outside the
scope of this change to be fixing it. Instead, any place where I saw
some sort of room for improvement has had a XXX comment added explaining
what could be altered to improve it.
Change-Id: I37a84def5ea4ddf93868ce8105f39de078297fbf
											 
										 
										
											2015-12-23 15:07:05 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									return  errors ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								unsigned  int  ast_odbc_class_get_isolation ( struct  odbc_class  * class )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  class - > isolation ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								unsigned  int  ast_odbc_class_get_forcecommit ( struct  odbc_class  * class )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  class - > forcecommit ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								const  char  * ast_odbc_class_get_name ( struct  odbc_class  * class )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  class - > name ; 
							 
						 
					
						
							
								
									
										
										
										
											2005-02-17 16:31:08 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2004-07-08 19:58:26 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								static  int  load_odbc_config ( void )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									static  char  * cfg  =  " res_odbc.conf " ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									struct  ast_config  * config ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									struct  ast_variable  * v ; 
							 
						 
					
						
							
								
									
										
										
										
											2007-11-14 15:13:22 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									char  * cat ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									const  char  * dsn ,  * username ,  * password ,  * sanitysql ; 
							 
						 
					
						
							
								
									
										
											 
										
											
												res_odbc: Remove connection management
Asterisk by default will create a single database connection and share
it among all threads that attempt to access the database. In previous
versions of Asterisk, this was tolerable, because the most used channel
driver, chan_sip, mostly accessed the database from a single thread.
With PJSIP, however, many threads may be attempting to perform database
operations, and there is the potential for many more database accesses,
meaning the concurrency is a horrible bottleneck if only one connection
is shared.
Asterisk has a connection pooling facility built into it, but the
implementation has flaws. For one, there is a strict limit on the number
of simultaneous connections that could be made to the database. Anything
beyond the maximum would result in a failed operation. Attempting to
predict what the maximum should be is nearly impossible even for someone
intimately familiar with Asterisk's threading model. In addition, use of
transactions in the dialplan can cause some severe bugs if connection
pooling is enabled.
This commit seeks to fix the concurrency problem by removing all
connection management code from Asterisk and leaving that to the
underlying unixODBC code instead. Now, Asterisk does not share a single
connection, nor does it try to maintain a connection pool. Instead, all
Asterisk ever does is request a connection from unixODBC and allow
unixODBC to either allocate those connections or retrieve them from a
pool.
Doing this has a bit of a ripple effect. For one, since connections are
not long-lived objects, several of the safeguards that previously
existed have been removed. We don't have to worry about trying to use a
connection that has gone stale. In every case, when we request a
connection, it has just been made and we don't need to perform any
sanity checks to be sure it's still active.
Another major player affected by this change is transactions.
Transactions and their respective connections were so tightly coupled
that it was almost pornographic. This code change moves
transaction-related code to its own file separate from the core ODBC
functionality. This way, the core of ODBC does not even have to know
that transactions exist.
In making this large change, I had to look at a lot of code and
understand it. When making this change, I discovered several places
where the behavior is definitely not ideal, but it seemed outside the
scope of this change to be fixing it. Instead, any place where I saw
some sort of room for improvement has had a XXX comment added explaining
what could be altered to improve it.
Change-Id: I37a84def5ea4ddf93868ce8105f39de078297fbf
											 
										 
										
											2015-12-23 15:07:05 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									int  enabled ,  bse ,  conntimeout ,  forcecommit ,  isolation ; 
							 
						 
					
						
							
								
									
										
										
										
											2010-07-23 16:19:21 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									struct  timeval  ncache  =  {  0 ,  0  } ; 
							 
						 
					
						
							
								
									
										
										
										
											2008-08-10 00:47:56 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									int  preconnect  =  0 ,  res  =  0 ; 
							 
						 
					
						
							
								
									
										
										
										
											2007-08-16 21:09:46 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									struct  ast_flags  config_flags  =  {  0  } ; 
							 
						 
					
						
							
								
									
										
										
										
											2004-07-08 19:58:26 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2006-04-18 18:16:32 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									struct  odbc_class  * new ; 
							 
						 
					
						
							
								
									
										
										
										
											2004-07-08 19:58:26 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2007-08-16 21:09:46 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									config  =  ast_config_load ( cfg ,  config_flags ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2008-09-12 23:30:03 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  ( config  = =  CONFIG_STATUS_FILEMISSING  | |  config  = =  CONFIG_STATUS_FILEINVALID )  { 
							 
						 
					
						
							
								
									
										
										
										
											2006-08-31 21:00:20 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										ast_log ( LOG_WARNING ,  " Unable to load config file res_odbc.conf \n " ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  - 1 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									for  ( cat  =  ast_category_browse ( config ,  NULL ) ;  cat ;  cat = ast_category_browse ( config ,  cat ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ( ! strcasecmp ( cat ,  " ENV " ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											for  ( v  =  ast_variable_browse ( config ,  cat ) ;  v ;  v  =  v - > next )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												setenv ( v - > name ,  v - > value ,  1 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												ast_log ( LOG_NOTICE ,  " Adding ENV var: %s=%s \n " ,  v - > name ,  v - > value ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										}  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											/* Reset all to defaults for each class of odbc connections */ 
							 
						 
					
						
							
								
									
										
										
										
											2006-11-13 05:58:14 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											dsn  =  username  =  password  =  sanitysql  =  NULL ; 
							 
						 
					
						
							
								
									
										
										
										
											2006-08-31 21:00:20 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											enabled  =  1 ; 
							 
						 
					
						
							
								
									
										
											 
										
											
												res_odbc: Remove connection management
Asterisk by default will create a single database connection and share
it among all threads that attempt to access the database. In previous
versions of Asterisk, this was tolerable, because the most used channel
driver, chan_sip, mostly accessed the database from a single thread.
With PJSIP, however, many threads may be attempting to perform database
operations, and there is the potential for many more database accesses,
meaning the concurrency is a horrible bottleneck if only one connection
is shared.
Asterisk has a connection pooling facility built into it, but the
implementation has flaws. For one, there is a strict limit on the number
of simultaneous connections that could be made to the database. Anything
beyond the maximum would result in a failed operation. Attempting to
predict what the maximum should be is nearly impossible even for someone
intimately familiar with Asterisk's threading model. In addition, use of
transactions in the dialplan can cause some severe bugs if connection
pooling is enabled.
This commit seeks to fix the concurrency problem by removing all
connection management code from Asterisk and leaving that to the
underlying unixODBC code instead. Now, Asterisk does not share a single
connection, nor does it try to maintain a connection pool. Instead, all
Asterisk ever does is request a connection from unixODBC and allow
unixODBC to either allocate those connections or retrieve them from a
pool.
Doing this has a bit of a ripple effect. For one, since connections are
not long-lived objects, several of the safeguards that previously
existed have been removed. We don't have to worry about trying to use a
connection that has gone stale. In every case, when we request a
connection, it has just been made and we don't need to perform any
sanity checks to be sure it's still active.
Another major player affected by this change is transactions.
Transactions and their respective connections were so tightly coupled
that it was almost pornographic. This code change moves
transaction-related code to its own file separate from the core ODBC
functionality. This way, the core of ODBC does not even have to know
that transactions exist.
In making this large change, I had to look at a lot of code and
understand it. When making this change, I discovered several places
where the behavior is definitely not ideal, but it seemed outside the
scope of this change to be fixing it. Instead, any place where I saw
some sort of room for improvement has had a XXX comment added explaining
what could be altered to improve it.
Change-Id: I37a84def5ea4ddf93868ce8105f39de078297fbf
											 
										 
										
											2015-12-23 15:07:05 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											preconnect  =  0 ; 
							 
						 
					
						
							
								
									
										
										
										
											2007-11-25 17:50:07 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											bse  =  1 ; 
							 
						 
					
						
							
								
									
										
										
										
											2010-08-25 16:14:11 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											conntimeout  =  10 ; 
							 
						 
					
						
							
								
									
										
										
										
											2009-02-19 00:26:01 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											forcecommit  =  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											isolation  =  SQL_TXN_READ_COMMITTED ; 
							 
						 
					
						
							
								
									
										
										
										
											2006-08-31 21:00:20 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											for  ( v  =  ast_variable_browse ( config ,  cat ) ;  v ;  v  =  v - > next )  { 
							 
						 
					
						
							
								
									
										
											 
										
											
												res_odbc: Remove connection management
Asterisk by default will create a single database connection and share
it among all threads that attempt to access the database. In previous
versions of Asterisk, this was tolerable, because the most used channel
driver, chan_sip, mostly accessed the database from a single thread.
With PJSIP, however, many threads may be attempting to perform database
operations, and there is the potential for many more database accesses,
meaning the concurrency is a horrible bottleneck if only one connection
is shared.
Asterisk has a connection pooling facility built into it, but the
implementation has flaws. For one, there is a strict limit on the number
of simultaneous connections that could be made to the database. Anything
beyond the maximum would result in a failed operation. Attempting to
predict what the maximum should be is nearly impossible even for someone
intimately familiar with Asterisk's threading model. In addition, use of
transactions in the dialplan can cause some severe bugs if connection
pooling is enabled.
This commit seeks to fix the concurrency problem by removing all
connection management code from Asterisk and leaving that to the
underlying unixODBC code instead. Now, Asterisk does not share a single
connection, nor does it try to maintain a connection pool. Instead, all
Asterisk ever does is request a connection from unixODBC and allow
unixODBC to either allocate those connections or retrieve them from a
pool.
Doing this has a bit of a ripple effect. For one, since connections are
not long-lived objects, several of the safeguards that previously
existed have been removed. We don't have to worry about trying to use a
connection that has gone stale. In every case, when we request a
connection, it has just been made and we don't need to perform any
sanity checks to be sure it's still active.
Another major player affected by this change is transactions.
Transactions and their respective connections were so tightly coupled
that it was almost pornographic. This code change moves
transaction-related code to its own file separate from the core ODBC
functionality. This way, the core of ODBC does not even have to know
that transactions exist.
In making this large change, I had to look at a lot of code and
understand it. When making this change, I discovered several places
where the behavior is definitely not ideal, but it seemed outside the
scope of this change to be fixing it. Instead, any place where I saw
some sort of room for improvement has had a XXX comment added explaining
what could be altered to improve it.
Change-Id: I37a84def5ea4ddf93868ce8105f39de078297fbf
											 
										 
										
											2015-12-23 15:07:05 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												if  ( ! strcasecmp ( v - > name ,  " pooling " )  | | 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
														! strncasecmp ( v - > name ,  " share " ,  5 )  | | 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
														! strcasecmp ( v - > name ,  " limit " )  | | 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
														! strcasecmp ( v - > name ,  " idlecheck " ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2016-02-03 13:07:07 -07:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
													ast_log ( LOG_WARNING ,  " The 'pooling', 'shared_connections', 'limit', and 'idlecheck' options are deprecated. Please see UPGRADE.txt for information \n " ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2006-08-31 21:00:20 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												}  else  if  ( ! strcasecmp ( v - > name ,  " enabled " ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													enabled  =  ast_true ( v - > value ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												}  else  if  ( ! strcasecmp ( v - > name ,  " pre-connect " ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2008-08-10 00:47:56 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
													preconnect  =  ast_true ( v - > value ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2006-08-31 21:00:20 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												}  else  if  ( ! strcasecmp ( v - > name ,  " dsn " ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													dsn  =  v - > value ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												}  else  if  ( ! strcasecmp ( v - > name ,  " username " ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													username  =  v - > value ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												}  else  if  ( ! strcasecmp ( v - > name ,  " password " ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													password  =  v - > value ; 
							 
						 
					
						
							
								
									
										
										
										
											2006-11-13 05:58:14 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												}  else  if  ( ! strcasecmp ( v - > name ,  " sanitysql " ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													sanitysql  =  v - > value ; 
							 
						 
					
						
							
								
									
										
										
										
											2007-11-25 17:50:07 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												}  else  if  ( ! strcasecmp ( v - > name ,  " backslash_is_escape " ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													bse  =  ast_true ( v - > value ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2010-07-23 16:19:21 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												}  else  if  ( ! strcasecmp ( v - > name ,  " connect_timeout " ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													if  ( sscanf ( v - > value ,  " %d " ,  & conntimeout )  ! =  1  | |  conntimeout  <  1 )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
														ast_log ( LOG_WARNING ,  " connect_timeout must be a positive integer \n " ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
														conntimeout  =  10 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												}  else  if  ( ! strcasecmp ( v - > name ,  " negative_connection_cache " ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													double  dncache ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													if  ( sscanf ( v - > value ,  " %lf " ,  & dncache )  ! =  1  | |  dncache  <  0 )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
														ast_log ( LOG_WARNING ,  " negative_connection_cache must be a non-negative integer \n " ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
														/* 5 minutes sounds like a reasonable default */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
														ncache . tv_sec  =  300 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
														ncache . tv_usec  =  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													}  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
														ncache . tv_sec  =  ( int ) dncache ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
														ncache . tv_usec  =  ( dncache  -  ncache . tv_sec )  *  1000000 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													} 
							 
						 
					
						
							
								
									
										
										
										
											2009-02-19 00:26:01 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												}  else  if  ( ! strcasecmp ( v - > name ,  " forcecommit " ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													forcecommit  =  ast_true ( v - > value ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												}  else  if  ( ! strcasecmp ( v - > name ,  " isolation " ) )  { 
							 
						 
					
						
							
								
									
										
											 
										
											
												res_odbc: Remove connection management
Asterisk by default will create a single database connection and share
it among all threads that attempt to access the database. In previous
versions of Asterisk, this was tolerable, because the most used channel
driver, chan_sip, mostly accessed the database from a single thread.
With PJSIP, however, many threads may be attempting to perform database
operations, and there is the potential for many more database accesses,
meaning the concurrency is a horrible bottleneck if only one connection
is shared.
Asterisk has a connection pooling facility built into it, but the
implementation has flaws. For one, there is a strict limit on the number
of simultaneous connections that could be made to the database. Anything
beyond the maximum would result in a failed operation. Attempting to
predict what the maximum should be is nearly impossible even for someone
intimately familiar with Asterisk's threading model. In addition, use of
transactions in the dialplan can cause some severe bugs if connection
pooling is enabled.
This commit seeks to fix the concurrency problem by removing all
connection management code from Asterisk and leaving that to the
underlying unixODBC code instead. Now, Asterisk does not share a single
connection, nor does it try to maintain a connection pool. Instead, all
Asterisk ever does is request a connection from unixODBC and allow
unixODBC to either allocate those connections or retrieve them from a
pool.
Doing this has a bit of a ripple effect. For one, since connections are
not long-lived objects, several of the safeguards that previously
existed have been removed. We don't have to worry about trying to use a
connection that has gone stale. In every case, when we request a
connection, it has just been made and we don't need to perform any
sanity checks to be sure it's still active.
Another major player affected by this change is transactions.
Transactions and their respective connections were so tightly coupled
that it was almost pornographic. This code change moves
transaction-related code to its own file separate from the core ODBC
functionality. This way, the core of ODBC does not even have to know
that transactions exist.
In making this large change, I had to look at a lot of code and
understand it. When making this change, I discovered several places
where the behavior is definitely not ideal, but it seemed outside the
scope of this change to be fixing it. Instead, any place where I saw
some sort of room for improvement has had a XXX comment added explaining
what could be altered to improve it.
Change-Id: I37a84def5ea4ddf93868ce8105f39de078297fbf
											 
										 
										
											2015-12-23 15:07:05 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
													if  ( ( isolation  =  ast_odbc_text2isolation ( v - > value ) )  = =  0 )  { 
							 
						 
					
						
							
								
									
										
										
										
											2009-02-19 00:26:01 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
														ast_log ( LOG_ERROR ,  " Unrecognized value for 'isolation': '%s' in section '%s' \n " ,  v - > value ,  cat ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
														isolation  =  SQL_TXN_READ_COMMITTED ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													} 
							 
						 
					
						
							
								
									
										
										
										
											2004-07-08 19:58:26 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												} 
							 
						 
					
						
							
								
									
										
										
										
											2006-08-31 21:00:20 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
									
										
										
										
											2004-07-08 19:58:26 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2006-08-31 21:00:20 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											if  ( enabled  & &  ! ast_strlen_zero ( dsn ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2008-05-05 23:38:15 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												new  =  ao2_alloc ( sizeof ( * new ) ,  odbc_class_destructor ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2004-07-08 19:58:26 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2006-08-31 21:00:20 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												if  ( ! new )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													res  =  - 1 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													break ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												} 
							 
						 
					
						
							
								
									
										
										
										
											2004-07-08 19:58:26 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2006-08-31 21:00:20 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												SQLAllocHandle ( SQL_HANDLE_ENV ,  SQL_NULL_HANDLE ,  & new - > env ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												res  =  SQLSetEnvAttr ( new - > env ,  SQL_ATTR_ODBC_VERSION ,  ( void  * )  SQL_OV_ODBC3 ,  0 ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2006-04-18 18:16:32 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2006-08-31 21:00:20 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												if  ( ( res  ! =  SQL_SUCCESS )  & &  ( res  ! =  SQL_SUCCESS_WITH_INFO ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													ast_log ( LOG_WARNING ,  " res_odbc: Error SetEnv \n " ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2008-05-05 23:38:15 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
													ao2_ref ( new ,  - 1 ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2006-08-31 21:00:20 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
													return  res ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												} 
							 
						 
					
						
							
								
									
										
										
										
											2006-04-18 18:16:32 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2007-11-25 17:50:07 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												new - > backslash_is_escape  =  bse  ?  1  :  0 ; 
							 
						 
					
						
							
								
									
										
										
										
											2009-02-19 00:26:01 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												new - > forcecommit  =  forcecommit  ?  1  :  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												new - > isolation  =  isolation ; 
							 
						 
					
						
							
								
									
										
										
										
											2010-07-23 16:19:21 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												new - > conntimeout  =  conntimeout ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												new - > negative_connection_cache  =  ncache ; 
							 
						 
					
						
							
								
									
										
										
										
											2007-11-25 17:50:07 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2008-05-05 23:38:15 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												if  ( cat ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													ast_copy_string ( new - > name ,  cat ,  sizeof ( new - > name ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												if  ( dsn ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													ast_copy_string ( new - > dsn ,  dsn ,  sizeof ( new - > dsn ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												if  ( username  & &  ! ( new - > username  =  ast_strdup ( username ) ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													ao2_ref ( new ,  - 1 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													break ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												if  ( password  & &  ! ( new - > password  =  ast_strdup ( password ) ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													ao2_ref ( new ,  - 1 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													break ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												if  ( sanitysql  & &  ! ( new - > sanitysql  =  ast_strdup ( sanitysql ) ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													ao2_ref ( new ,  - 1 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													break ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2008-08-10 00:47:56 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												odbc_register_class ( new ,  preconnect ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2006-08-31 21:00:20 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												ast_log ( LOG_NOTICE ,  " Registered ODBC class '%s' dsn->[%s] \n " ,  cat ,  dsn ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2008-05-05 23:38:15 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												ao2_ref ( new ,  - 1 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												new  =  NULL ; 
							 
						 
					
						
							
								
									
										
										
										
											2004-07-08 19:58:26 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2004-06-11 00:12:35 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2006-08-31 21:00:20 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									ast_config_destroy ( config ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2006-04-18 18:16:32 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									return  res ; 
							 
						 
					
						
							
								
									
										
										
										
											2005-01-07 06:36:02 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2007-09-18 22:43:45 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								static  char  * handle_cli_odbc_show ( struct  ast_cli_entry  * e ,  int  cmd ,  struct  ast_cli_args  * a )  
						 
					
						
							
								
									
										
										
										
											2004-07-08 19:58:26 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
									
										
										
										
											2012-01-27 18:47:16 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									struct  ao2_iterator  aoi ; 
							 
						 
					
						
							
								
									
										
										
										
											2006-04-18 18:16:32 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									struct  odbc_class  * class ; 
							 
						 
					
						
							
								
									
										
										
										
											2007-09-18 22:43:45 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									int  length  =  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									int  which  =  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									char  * ret  =  NULL ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									switch  ( cmd )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									case  CLI_INIT : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										e - > command  =  " odbc show " ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										e - > usage  = 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												" Usage: odbc show [class] \n " 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												"        List settings of a particular ODBC class or, \n " 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												"        if not specified, all classes. \n " ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  NULL ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									case  CLI_GENERATE : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ( a - > pos  ! =  2 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  NULL ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										length  =  strlen ( a - > word ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2012-01-27 18:47:16 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										aoi  =  ao2_iterator_init ( class_container ,  0 ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2008-05-05 23:38:15 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										while  ( ( class  =  ao2_iterator_next ( & aoi ) ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2007-09-18 22:43:45 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											if  ( ! strncasecmp ( a - > word ,  class - > name ,  length )  & &  + + which  >  a - > n )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												ret  =  ast_strdup ( class - > name ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
									
										
										
										
											2008-05-05 23:38:15 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											ao2_ref ( class ,  - 1 ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2009-02-17 18:49:20 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											if  ( ret )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												break ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
									
										
										
										
											2007-09-18 22:43:45 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2009-10-06 01:24:24 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										ao2_iterator_destroy ( & aoi ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2007-09-18 22:43:45 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  ( ! ret  & &  ! strncasecmp ( a - > word ,  " all " ,  length )  & &  + + which  >  a - > n )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ret  =  ast_strdup ( " all " ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  ret ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2004-07-08 19:58:26 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2007-09-18 22:43:45 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									ast_cli ( a - > fd ,  " \n ODBC DSN Settings \n " ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2008-05-05 23:38:15 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									ast_cli ( a - > fd ,    " ----------------- \n \n " ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									aoi  =  ao2_iterator_init ( class_container ,  0 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									while  ( ( class  =  ao2_iterator_next ( & aoi ) ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2007-09-18 22:43:45 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  ( ( a - > argc  = =  2 )  | |  ( a - > argc  = =  3  & &  ! strcmp ( a - > argv [ 2 ] ,  " all " ) )  | |  ( ! strcmp ( a - > argv [ 2 ] ,  class - > name ) ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2010-07-23 16:19:21 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											char  timestr [ 80 ] ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											struct  ast_tm  tm ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ast_localtime ( & class - > last_negative_connect ,  & tm ,  NULL ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ast_strftime ( timestr ,  sizeof ( timestr ) ,  " %Y-%m-%d %T " ,  & tm ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2007-09-18 22:43:45 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											ast_cli ( a - > fd ,  "   Name:   %s \n   DSN:    %s \n " ,  class - > name ,  class - > dsn ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2010-07-23 16:19:21 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											ast_cli ( a - > fd ,  "     Last connection attempt: %s \n " ,  timestr ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2007-09-18 22:43:45 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											ast_cli ( a - > fd ,  " \n " ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2005-01-07 06:36:02 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2008-05-05 23:38:15 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										ao2_ref ( class ,  - 1 ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2004-07-08 19:58:26 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2009-10-06 01:24:24 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									ao2_iterator_destroy ( & aoi ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2006-09-18 19:54:18 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2007-09-18 22:43:45 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									return  CLI_SUCCESS ; 
							 
						 
					
						
							
								
									
										
										
										
											2004-06-11 00:12:35 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2006-09-18 19:54:18 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								static  struct  ast_cli_entry  cli_odbc [ ]  =  {  
						 
					
						
							
								
									
										
										
										
											2007-10-22 20:05:18 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									AST_CLI_DEFINE ( handle_cli_odbc_show ,  " List ODBC DSN(s) " ) 
							 
						 
					
						
							
								
									
										
										
										
											2006-09-18 19:54:18 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								} ;  
						 
					
						
							
								
									
										
										
										
											2004-06-11 00:12:35 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2008-08-10 00:47:56 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								static  int  odbc_register_class ( struct  odbc_class  * class ,  int  preconnect )  
						 
					
						
							
								
									
										
										
										
											2004-07-08 19:58:26 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
									
										
										
										
											2006-04-18 18:16:32 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									struct  odbc_obj  * obj ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( class )  { 
							 
						 
					
						
							
								
									
										
										
										
											2008-05-05 23:38:15 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										ao2_link ( class_container ,  class ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										/* I still have a reference in the caller, so a deref is NOT missing here. */ 
							 
						 
					
						
							
								
									
										
										
										
											2006-04-18 18:16:32 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2008-08-10 00:47:56 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  ( preconnect )  { 
							 
						 
					
						
							
								
									
										
										
										
											2006-04-18 18:16:32 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											/* Request and release builds a connection */ 
							 
						 
					
						
							
								
									
										
										
										
											2006-09-20 04:57:20 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											obj  =  ast_odbc_request_obj ( class - > name ,  0 ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2009-02-19 00:26:01 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											if  ( obj )  { 
							 
						 
					
						
							
								
									
										
										
										
											2007-01-30 09:10:09 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												ast_odbc_release_obj ( obj ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2009-02-19 00:26:01 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
									
										
										
										
											2006-04-18 18:16:32 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2004-06-11 00:12:35 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2006-04-18 18:16:32 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										return  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									}  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_log ( LOG_WARNING ,  " Attempted to register a NULL class? \n " ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  - 1 ; 
							 
						 
					
						
							
								
									
										
										
										
											2005-02-17 16:31:08 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2004-06-11 00:12:35 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
											 
										
											
												res_odbc: Remove connection management
Asterisk by default will create a single database connection and share
it among all threads that attempt to access the database. In previous
versions of Asterisk, this was tolerable, because the most used channel
driver, chan_sip, mostly accessed the database from a single thread.
With PJSIP, however, many threads may be attempting to perform database
operations, and there is the potential for many more database accesses,
meaning the concurrency is a horrible bottleneck if only one connection
is shared.
Asterisk has a connection pooling facility built into it, but the
implementation has flaws. For one, there is a strict limit on the number
of simultaneous connections that could be made to the database. Anything
beyond the maximum would result in a failed operation. Attempting to
predict what the maximum should be is nearly impossible even for someone
intimately familiar with Asterisk's threading model. In addition, use of
transactions in the dialplan can cause some severe bugs if connection
pooling is enabled.
This commit seeks to fix the concurrency problem by removing all
connection management code from Asterisk and leaving that to the
underlying unixODBC code instead. Now, Asterisk does not share a single
connection, nor does it try to maintain a connection pool. Instead, all
Asterisk ever does is request a connection from unixODBC and allow
unixODBC to either allocate those connections or retrieve them from a
pool.
Doing this has a bit of a ripple effect. For one, since connections are
not long-lived objects, several of the safeguards that previously
existed have been removed. We don't have to worry about trying to use a
connection that has gone stale. In every case, when we request a
connection, it has just been made and we don't need to perform any
sanity checks to be sure it's still active.
Another major player affected by this change is transactions.
Transactions and their respective connections were so tightly coupled
that it was almost pornographic. This code change moves
transaction-related code to its own file separate from the core ODBC
functionality. This way, the core of ODBC does not even have to know
that transactions exist.
In making this large change, I had to look at a lot of code and
understand it. When making this change, I discovered several places
where the behavior is definitely not ideal, but it seemed outside the
scope of this change to be fixing it. Instead, any place where I saw
some sort of room for improvement has had a XXX comment added explaining
what could be altered to improve it.
Change-Id: I37a84def5ea4ddf93868ce8105f39de078297fbf
											 
										 
										
											2015-12-23 15:07:05 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								void  ast_odbc_release_obj ( struct  odbc_obj  * obj )  
						 
					
						
							
								
									
										
										
										
											2004-07-08 19:58:26 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
									
										
											 
										
											
												res_odbc: Remove connection management
Asterisk by default will create a single database connection and share
it among all threads that attempt to access the database. In previous
versions of Asterisk, this was tolerable, because the most used channel
driver, chan_sip, mostly accessed the database from a single thread.
With PJSIP, however, many threads may be attempting to perform database
operations, and there is the potential for many more database accesses,
meaning the concurrency is a horrible bottleneck if only one connection
is shared.
Asterisk has a connection pooling facility built into it, but the
implementation has flaws. For one, there is a strict limit on the number
of simultaneous connections that could be made to the database. Anything
beyond the maximum would result in a failed operation. Attempting to
predict what the maximum should be is nearly impossible even for someone
intimately familiar with Asterisk's threading model. In addition, use of
transactions in the dialplan can cause some severe bugs if connection
pooling is enabled.
This commit seeks to fix the concurrency problem by removing all
connection management code from Asterisk and leaving that to the
underlying unixODBC code instead. Now, Asterisk does not share a single
connection, nor does it try to maintain a connection pool. Instead, all
Asterisk ever does is request a connection from unixODBC and allow
unixODBC to either allocate those connections or retrieve them from a
pool.
Doing this has a bit of a ripple effect. For one, since connections are
not long-lived objects, several of the safeguards that previously
existed have been removed. We don't have to worry about trying to use a
connection that has gone stale. In every case, when we request a
connection, it has just been made and we don't need to perform any
sanity checks to be sure it's still active.
Another major player affected by this change is transactions.
Transactions and their respective connections were so tightly coupled
that it was almost pornographic. This code change moves
transaction-related code to its own file separate from the core ODBC
functionality. This way, the core of ODBC does not even have to know
that transactions exist.
In making this large change, I had to look at a lot of code and
understand it. When making this change, I discovered several places
where the behavior is definitely not ideal, but it seemed outside the
scope of this change to be fixing it. Instead, any place where I saw
some sort of room for improvement has had a XXX comment added explaining
what could be altered to improve it.
Change-Id: I37a84def5ea4ddf93868ce8105f39de078297fbf
											 
										 
										
											2015-12-23 15:07:05 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									ast_debug ( 2 ,  " Releasing ODBC handle %p \n " ,  obj ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2009-02-19 00:26:01 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2008-07-11 19:53:38 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								# ifdef DEBUG_THREADS 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									obj - > file [ 0 ]  =  ' \0 ' ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									obj - > function [ 0 ]  =  ' \0 ' ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									obj - > lineno  =  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# endif 
  
						 
					
						
							
								
									
										
										
										
											2008-05-05 23:38:15 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									ao2_ref ( obj ,  - 1 ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2006-04-18 18:16:32 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
									
										
										
										
											2004-07-08 19:58:26 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2007-11-25 17:50:07 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								int  ast_odbc_backslash_is_escape ( struct  odbc_obj  * obj )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  obj - > parent - > backslash_is_escape ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2009-02-19 00:26:01 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								static  int  aoro2_class_cb ( void  * obj ,  void  * arg ,  int  flags )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									struct  odbc_class  * class  =  obj ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									char  * name  =  arg ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( ! strcmp ( class - > name ,  name )  & &  ! class - > delme )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  CMP_MATCH  |  CMP_STOP ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								struct  odbc_obj  * _ast_odbc_request_obj2 ( const  char  * name ,  struct  ast_flags  flags ,  const  char  * file ,  const  char  * function ,  int  lineno )  
						 
					
						
							
								
									
										
										
										
											2006-04-18 18:16:32 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									struct  odbc_obj  * obj  =  NULL ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									struct  odbc_class  * class ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2009-02-19 00:26:01 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  ( ! ( class  =  ao2_callback ( class_container ,  0 ,  aoro2_class_cb ,  ( char  * )  name ) ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2010-08-26 13:28:05 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										ast_debug ( 1 ,  " Class '%s' not found! \n " ,  name ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2006-04-18 18:16:32 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										return  NULL ; 
							 
						 
					
						
							
								
									
										
										
										
											2009-02-19 00:26:01 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2006-04-18 18:16:32 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
											 
										
											
												res_odbc: Remove connection management
Asterisk by default will create a single database connection and share
it among all threads that attempt to access the database. In previous
versions of Asterisk, this was tolerable, because the most used channel
driver, chan_sip, mostly accessed the database from a single thread.
With PJSIP, however, many threads may be attempting to perform database
operations, and there is the potential for many more database accesses,
meaning the concurrency is a horrible bottleneck if only one connection
is shared.
Asterisk has a connection pooling facility built into it, but the
implementation has flaws. For one, there is a strict limit on the number
of simultaneous connections that could be made to the database. Anything
beyond the maximum would result in a failed operation. Attempting to
predict what the maximum should be is nearly impossible even for someone
intimately familiar with Asterisk's threading model. In addition, use of
transactions in the dialplan can cause some severe bugs if connection
pooling is enabled.
This commit seeks to fix the concurrency problem by removing all
connection management code from Asterisk and leaving that to the
underlying unixODBC code instead. Now, Asterisk does not share a single
connection, nor does it try to maintain a connection pool. Instead, all
Asterisk ever does is request a connection from unixODBC and allow
unixODBC to either allocate those connections or retrieve them from a
pool.
Doing this has a bit of a ripple effect. For one, since connections are
not long-lived objects, several of the safeguards that previously
existed have been removed. We don't have to worry about trying to use a
connection that has gone stale. In every case, when we request a
connection, it has just been made and we don't need to perform any
sanity checks to be sure it's still active.
Another major player affected by this change is transactions.
Transactions and their respective connections were so tightly coupled
that it was almost pornographic. This code change moves
transaction-related code to its own file separate from the core ODBC
functionality. This way, the core of ODBC does not even have to know
that transactions exist.
In making this large change, I had to look at a lot of code and
understand it. When making this change, I discovered several places
where the behavior is definitely not ideal, but it seemed outside the
scope of this change to be fixing it. Instead, any place where I saw
some sort of room for improvement has had a XXX comment added explaining
what could be altered to improve it.
Change-Id: I37a84def5ea4ddf93868ce8105f39de078297fbf
											 
										 
										
											2015-12-23 15:07:05 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									/* XXX ODBC connection objects do not have shared ownership, so there is no reason
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 *  to  use  refcounted  objects  here . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									obj  =  ao2_alloc ( sizeof ( * obj ) ,  odbc_obj_destructor ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/* Inherit reference from the ao2_callback from before */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									obj - > parent  =  class ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( odbc_obj_connect ( obj )  = =  ODBC_FAIL )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ao2_ref ( obj ,  - 1 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  NULL ; 
							 
						 
					
						
							
								
									
										
										
										
											2010-07-23 16:19:21 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2008-01-21 18:15:57 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2006-04-18 18:16:32 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									return  obj ; 
							 
						 
					
						
							
								
									
										
										
										
											2004-06-11 00:12:35 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2009-02-19 00:26:01 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								struct  odbc_obj  * _ast_odbc_request_obj ( const  char  * name ,  int  check ,  const  char  * file ,  const  char  * function ,  int  lineno )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									struct  ast_flags  flags  =  {  check  ?  RES_ODBC_SANITY_CHECK  :  0  } ; 
							 
						 
					
						
							
								
									
										
											 
										
											
												res_odbc: Remove connection management
Asterisk by default will create a single database connection and share
it among all threads that attempt to access the database. In previous
versions of Asterisk, this was tolerable, because the most used channel
driver, chan_sip, mostly accessed the database from a single thread.
With PJSIP, however, many threads may be attempting to perform database
operations, and there is the potential for many more database accesses,
meaning the concurrency is a horrible bottleneck if only one connection
is shared.
Asterisk has a connection pooling facility built into it, but the
implementation has flaws. For one, there is a strict limit on the number
of simultaneous connections that could be made to the database. Anything
beyond the maximum would result in a failed operation. Attempting to
predict what the maximum should be is nearly impossible even for someone
intimately familiar with Asterisk's threading model. In addition, use of
transactions in the dialplan can cause some severe bugs if connection
pooling is enabled.
This commit seeks to fix the concurrency problem by removing all
connection management code from Asterisk and leaving that to the
underlying unixODBC code instead. Now, Asterisk does not share a single
connection, nor does it try to maintain a connection pool. Instead, all
Asterisk ever does is request a connection from unixODBC and allow
unixODBC to either allocate those connections or retrieve them from a
pool.
Doing this has a bit of a ripple effect. For one, since connections are
not long-lived objects, several of the safeguards that previously
existed have been removed. We don't have to worry about trying to use a
connection that has gone stale. In every case, when we request a
connection, it has just been made and we don't need to perform any
sanity checks to be sure it's still active.
Another major player affected by this change is transactions.
Transactions and their respective connections were so tightly coupled
that it was almost pornographic. This code change moves
transaction-related code to its own file separate from the core ODBC
functionality. This way, the core of ODBC does not even have to know
that transactions exist.
In making this large change, I had to look at a lot of code and
understand it. When making this change, I discovered several places
where the behavior is definitely not ideal, but it seemed outside the
scope of this change to be fixing it. Instead, any place where I saw
some sort of room for improvement has had a XXX comment added explaining
what could be altered to improve it.
Change-Id: I37a84def5ea4ddf93868ce8105f39de078297fbf
											 
										 
										
											2015-12-23 15:07:05 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									/* XXX New flow means that the "check" parameter doesn't do anything. We're requesting
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 *  a  connection  from  ODBC .  We ' ll  either  get  a  new  one ,  which  obviously  is  already  connected ,  or 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 *  we ' ll  get  one  from  the  ODBC  connection  pool .  In  that  case ,  it  will  ensure  to  only  give  us  a 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 *  live  connection 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 */ 
							 
						 
					
						
							
								
									
										
										
										
											2009-02-19 00:26:01 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									return  _ast_odbc_request_obj2 ( name ,  flags ,  file ,  function ,  lineno ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2006-04-18 18:16:32 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								static  odbc_status  odbc_obj_disconnect ( struct  odbc_obj  * obj )  
						 
					
						
							
								
									
										
										
										
											2004-07-08 19:58:26 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									int  res ; 
							 
						 
					
						
							
								
									
										
										
										
											2008-08-11 00:25:28 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									SQLINTEGER  err ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									short  int  mlen ; 
							 
						 
					
						
							
								
									
										
										
										
											2008-10-08 12:15:06 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									unsigned  char  msg [ 200 ] ,  state [ 10 ] ; 
							 
						 
					
						
							
								
									
										
										
										
											2012-02-27 15:35:10 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									SQLHDBC  con ; 
							 
						 
					
						
							
								
									
										
										
										
											2008-08-11 00:25:28 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2008-10-02 15:17:16 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									/* Nothing to disconnect */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( ! obj - > con )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  ODBC_SUCCESS ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2012-02-27 15:35:10 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									con  =  obj - > con ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									obj - > con  =  NULL ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									res  =  SQLDisconnect ( con ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2005-02-17 16:31:08 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2009-02-17 18:49:20 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  ( obj - > parent )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ( res  = =  SQL_SUCCESS  | |  res  = =  SQL_SUCCESS_WITH_INFO )  { 
							 
						 
					
						
							
								
									
										
											 
										
											
												res_odbc: Remove connection management
Asterisk by default will create a single database connection and share
it among all threads that attempt to access the database. In previous
versions of Asterisk, this was tolerable, because the most used channel
driver, chan_sip, mostly accessed the database from a single thread.
With PJSIP, however, many threads may be attempting to perform database
operations, and there is the potential for many more database accesses,
meaning the concurrency is a horrible bottleneck if only one connection
is shared.
Asterisk has a connection pooling facility built into it, but the
implementation has flaws. For one, there is a strict limit on the number
of simultaneous connections that could be made to the database. Anything
beyond the maximum would result in a failed operation. Attempting to
predict what the maximum should be is nearly impossible even for someone
intimately familiar with Asterisk's threading model. In addition, use of
transactions in the dialplan can cause some severe bugs if connection
pooling is enabled.
This commit seeks to fix the concurrency problem by removing all
connection management code from Asterisk and leaving that to the
underlying unixODBC code instead. Now, Asterisk does not share a single
connection, nor does it try to maintain a connection pool. Instead, all
Asterisk ever does is request a connection from unixODBC and allow
unixODBC to either allocate those connections or retrieve them from a
pool.
Doing this has a bit of a ripple effect. For one, since connections are
not long-lived objects, several of the safeguards that previously
existed have been removed. We don't have to worry about trying to use a
connection that has gone stale. In every case, when we request a
connection, it has just been made and we don't need to perform any
sanity checks to be sure it's still active.
Another major player affected by this change is transactions.
Transactions and their respective connections were so tightly coupled
that it was almost pornographic. This code change moves
transaction-related code to its own file separate from the core ODBC
functionality. This way, the core of ODBC does not even have to know
that transactions exist.
In making this large change, I had to look at a lot of code and
understand it. When making this change, I discovered several places
where the behavior is definitely not ideal, but it seemed outside the
scope of this change to be fixing it. Instead, any place where I saw
some sort of room for improvement has had a XXX comment added explaining
what could be altered to improve it.
Change-Id: I37a84def5ea4ddf93868ce8105f39de078297fbf
											 
										 
										
											2015-12-23 15:07:05 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											ast_debug ( 3 ,  " Disconnected %d from %s [%s](%p) \n " ,  res ,  obj - > parent - > name ,  obj - > parent - > dsn ,  obj ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2009-02-17 18:49:20 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										}  else  { 
							 
						 
					
						
							
								
									
										
											 
										
											
												res_odbc: Remove connection management
Asterisk by default will create a single database connection and share
it among all threads that attempt to access the database. In previous
versions of Asterisk, this was tolerable, because the most used channel
driver, chan_sip, mostly accessed the database from a single thread.
With PJSIP, however, many threads may be attempting to perform database
operations, and there is the potential for many more database accesses,
meaning the concurrency is a horrible bottleneck if only one connection
is shared.
Asterisk has a connection pooling facility built into it, but the
implementation has flaws. For one, there is a strict limit on the number
of simultaneous connections that could be made to the database. Anything
beyond the maximum would result in a failed operation. Attempting to
predict what the maximum should be is nearly impossible even for someone
intimately familiar with Asterisk's threading model. In addition, use of
transactions in the dialplan can cause some severe bugs if connection
pooling is enabled.
This commit seeks to fix the concurrency problem by removing all
connection management code from Asterisk and leaving that to the
underlying unixODBC code instead. Now, Asterisk does not share a single
connection, nor does it try to maintain a connection pool. Instead, all
Asterisk ever does is request a connection from unixODBC and allow
unixODBC to either allocate those connections or retrieve them from a
pool.
Doing this has a bit of a ripple effect. For one, since connections are
not long-lived objects, several of the safeguards that previously
existed have been removed. We don't have to worry about trying to use a
connection that has gone stale. In every case, when we request a
connection, it has just been made and we don't need to perform any
sanity checks to be sure it's still active.
Another major player affected by this change is transactions.
Transactions and their respective connections were so tightly coupled
that it was almost pornographic. This code change moves
transaction-related code to its own file separate from the core ODBC
functionality. This way, the core of ODBC does not even have to know
that transactions exist.
In making this large change, I had to look at a lot of code and
understand it. When making this change, I discovered several places
where the behavior is definitely not ideal, but it seemed outside the
scope of this change to be fixing it. Instead, any place where I saw
some sort of room for improvement has had a XXX comment added explaining
what could be altered to improve it.
Change-Id: I37a84def5ea4ddf93868ce8105f39de078297fbf
											 
										 
										
											2015-12-23 15:07:05 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											ast_debug ( 3 ,  " res_odbc: %s [%s](%p) already disconnected \n " ,  obj - > parent - > name ,  obj - > parent - > dsn ,  obj ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2009-02-17 18:49:20 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2004-07-08 19:58:26 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2008-08-11 00:25:28 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2012-04-17 18:57:40 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  ( ( res  =  SQLFreeHandle ( SQL_HANDLE_DBC ,  con ) )  = =  SQL_SUCCESS )  { 
							 
						 
					
						
							
								
									
										
											 
										
											
												res_odbc: Remove connection management
Asterisk by default will create a single database connection and share
it among all threads that attempt to access the database. In previous
versions of Asterisk, this was tolerable, because the most used channel
driver, chan_sip, mostly accessed the database from a single thread.
With PJSIP, however, many threads may be attempting to perform database
operations, and there is the potential for many more database accesses,
meaning the concurrency is a horrible bottleneck if only one connection
is shared.
Asterisk has a connection pooling facility built into it, but the
implementation has flaws. For one, there is a strict limit on the number
of simultaneous connections that could be made to the database. Anything
beyond the maximum would result in a failed operation. Attempting to
predict what the maximum should be is nearly impossible even for someone
intimately familiar with Asterisk's threading model. In addition, use of
transactions in the dialplan can cause some severe bugs if connection
pooling is enabled.
This commit seeks to fix the concurrency problem by removing all
connection management code from Asterisk and leaving that to the
underlying unixODBC code instead. Now, Asterisk does not share a single
connection, nor does it try to maintain a connection pool. Instead, all
Asterisk ever does is request a connection from unixODBC and allow
unixODBC to either allocate those connections or retrieve them from a
pool.
Doing this has a bit of a ripple effect. For one, since connections are
not long-lived objects, several of the safeguards that previously
existed have been removed. We don't have to worry about trying to use a
connection that has gone stale. In every case, when we request a
connection, it has just been made and we don't need to perform any
sanity checks to be sure it's still active.
Another major player affected by this change is transactions.
Transactions and their respective connections were so tightly coupled
that it was almost pornographic. This code change moves
transaction-related code to its own file separate from the core ODBC
functionality. This way, the core of ODBC does not even have to know
that transactions exist.
In making this large change, I had to look at a lot of code and
understand it. When making this change, I discovered several places
where the behavior is definitely not ideal, but it seemed outside the
scope of this change to be fixing it. Instead, any place where I saw
some sort of room for improvement has had a XXX comment added explaining
what could be altered to improve it.
Change-Id: I37a84def5ea4ddf93868ce8105f39de078297fbf
											 
										 
										
											2015-12-23 15:07:05 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										ast_debug ( 3 ,  " Database handle %p (connection %p) deallocated \n " ,  obj ,  con ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2008-08-11 00:25:28 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									}  else  { 
							 
						 
					
						
							
								
									
										
										
										
											2012-02-27 15:35:10 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										SQLGetDiagRec ( SQL_HANDLE_DBC ,  con ,  1 ,  state ,  & err ,  msg ,  100 ,  & mlen ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_log ( LOG_WARNING ,  " Unable to deallocate database handle %p? %d errno=%d %s \n " ,  con ,  res ,  ( int ) err ,  msg ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2008-08-11 00:25:28 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2004-07-08 19:58:26 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									return  ODBC_SUCCESS ; 
							 
						 
					
						
							
								
									
										
										
										
											2004-06-11 00:12:35 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2006-04-18 18:16:32 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								static  odbc_status  odbc_obj_connect ( struct  odbc_obj  * obj )  
						 
					
						
							
								
									
										
										
										
											2004-07-08 19:58:26 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									int  res ; 
							 
						 
					
						
							
								
									
										
										
										
											2005-09-02 19:29:18 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									SQLINTEGER  err ; 
							 
						 
					
						
							
								
									
										
										
										
											2004-07-08 19:58:26 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									short  int  mlen ; 
							 
						 
					
						
							
								
									
										
										
										
											2008-08-10 00:47:56 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									unsigned  char  msg [ 200 ] ,  state [ 10 ] ; 
							 
						 
					
						
							
								
									
										
										
										
											2006-04-18 18:16:32 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								# ifdef NEEDTRACE 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									SQLINTEGER  enable  =  1 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									char  * tracefile  =  " /tmp/odbc.trace " ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# endif 
  
						 
					
						
							
								
									
										
										
										
											2012-02-27 15:35:10 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									SQLHDBC  con ; 
							 
						 
					
						
							
								
									
										
										
										
											2015-04-21 18:52:22 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									long  int  negative_cache_expiration ; 
							 
						 
					
						
							
								
									
										
										
										
											2004-06-11 00:12:35 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
											 
										
											
												res_odbc: Remove connection management
Asterisk by default will create a single database connection and share
it among all threads that attempt to access the database. In previous
versions of Asterisk, this was tolerable, because the most used channel
driver, chan_sip, mostly accessed the database from a single thread.
With PJSIP, however, many threads may be attempting to perform database
operations, and there is the potential for many more database accesses,
meaning the concurrency is a horrible bottleneck if only one connection
is shared.
Asterisk has a connection pooling facility built into it, but the
implementation has flaws. For one, there is a strict limit on the number
of simultaneous connections that could be made to the database. Anything
beyond the maximum would result in a failed operation. Attempting to
predict what the maximum should be is nearly impossible even for someone
intimately familiar with Asterisk's threading model. In addition, use of
transactions in the dialplan can cause some severe bugs if connection
pooling is enabled.
This commit seeks to fix the concurrency problem by removing all
connection management code from Asterisk and leaving that to the
underlying unixODBC code instead. Now, Asterisk does not share a single
connection, nor does it try to maintain a connection pool. Instead, all
Asterisk ever does is request a connection from unixODBC and allow
unixODBC to either allocate those connections or retrieve them from a
pool.
Doing this has a bit of a ripple effect. For one, since connections are
not long-lived objects, several of the safeguards that previously
existed have been removed. We don't have to worry about trying to use a
connection that has gone stale. In every case, when we request a
connection, it has just been made and we don't need to perform any
sanity checks to be sure it's still active.
Another major player affected by this change is transactions.
Transactions and their respective connections were so tightly coupled
that it was almost pornographic. This code change moves
transaction-related code to its own file separate from the core ODBC
functionality. This way, the core of ODBC does not even have to know
that transactions exist.
In making this large change, I had to look at a lot of code and
understand it. When making this change, I discovered several places
where the behavior is definitely not ideal, but it seemed outside the
scope of this change to be fixing it. Instead, any place where I saw
some sort of room for improvement has had a XXX comment added explaining
what could be altered to improve it.
Change-Id: I37a84def5ea4ddf93868ce8105f39de078297fbf
											 
										 
										
											2015-12-23 15:07:05 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									ast_assert ( obj - > con  = =  NULL ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ast_debug ( 3 ,  " Connecting %s(%p) \n " ,  obj - > parent - > name ,  obj ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2008-10-02 15:17:16 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2015-04-21 18:52:22 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									/* Dont connect while server is marked as unreachable via negative_connection_cache */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									negative_cache_expiration  =  obj - > parent - > last_negative_connect . tv_sec  +  obj - > parent - > negative_connection_cache . tv_sec ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( time ( NULL )  <  negative_cache_expiration )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_log ( LOG_WARNING ,  " Not connecting to %s. Negative connection cache for %ld seconds \n " ,  obj - > parent - > name ,  negative_cache_expiration  -  time ( NULL ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  ODBC_FAIL ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2012-02-27 15:35:10 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									res  =  SQLAllocHandle ( SQL_HANDLE_DBC ,  obj - > parent - > env ,  & con ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2004-06-11 00:12:35 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2006-04-18 18:16:32 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  ( ( res  ! =  SQL_SUCCESS )  & &  ( res  ! =  SQL_SUCCESS_WITH_INFO ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_log ( LOG_WARNING ,  " res_odbc: Error AllocHDB %d \n " ,  res ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2010-07-23 16:19:21 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										obj - > parent - > last_negative_connect  =  ast_tvnow ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2006-04-18 18:16:32 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										return  ODBC_FAIL ; 
							 
						 
					
						
							
								
									
										
										
										
											2004-07-08 19:58:26 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2012-02-27 15:35:10 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									SQLSetConnectAttr ( con ,  SQL_LOGIN_TIMEOUT ,  ( SQLPOINTER  * ) ( long )  obj - > parent - > conntimeout ,  0 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									SQLSetConnectAttr ( con ,  SQL_ATTR_CONNECTION_TIMEOUT ,  ( SQLPOINTER  * ) ( long )  obj - > parent - > conntimeout ,  0 ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2006-04-18 18:16:32 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								# ifdef NEEDTRACE 
  
						 
					
						
							
								
									
										
										
										
											2012-02-27 15:35:10 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									SQLSetConnectAttr ( con ,  SQL_ATTR_TRACE ,  & enable ,  SQL_IS_INTEGER ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									SQLSetConnectAttr ( con ,  SQL_ATTR_TRACEFILE ,  tracefile ,  strlen ( tracefile ) ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2006-04-18 18:16:32 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								# endif 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2012-02-27 15:35:10 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									res  =  SQLConnect ( con , 
							 
						 
					
						
							
								
									
										
										
										
											2006-04-18 18:16:32 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										   ( SQLCHAR  * )  obj - > parent - > dsn ,  SQL_NTS , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										   ( SQLCHAR  * )  obj - > parent - > username ,  SQL_NTS , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										   ( SQLCHAR  * )  obj - > parent - > password ,  SQL_NTS ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2004-07-08 19:58:26 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( ( res  ! =  SQL_SUCCESS )  & &  ( res  ! =  SQL_SUCCESS_WITH_INFO ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2012-02-27 15:35:10 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										SQLGetDiagRec ( SQL_HANDLE_DBC ,  con ,  1 ,  state ,  & err ,  msg ,  100 ,  & mlen ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2010-07-23 16:19:21 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										obj - > parent - > last_negative_connect  =  ast_tvnow ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2005-09-02 19:29:18 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										ast_log ( LOG_WARNING ,  " res_odbc: Error SQLConnect=%d errno=%d %s \n " ,  res ,  ( int ) err ,  msg ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2012-04-17 18:57:40 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  ( ( res  =  SQLFreeHandle ( SQL_HANDLE_DBC ,  con ) )  ! =  SQL_SUCCESS )  { 
							 
						 
					
						
							
								
									
										
										
										
											2012-02-27 15:35:10 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											SQLGetDiagRec ( SQL_HANDLE_DBC ,  con ,  1 ,  state ,  & err ,  msg ,  100 ,  & mlen ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ast_log ( LOG_WARNING ,  " Unable to deallocate database handle %p? %d errno=%d %s \n " ,  con ,  res ,  ( int ) err ,  msg ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2004-07-08 19:58:26 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										return  ODBC_FAIL ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									}  else  { 
							 
						 
					
						
							
								
									
										
											 
										
											
												res_odbc: Remove connection management
Asterisk by default will create a single database connection and share
it among all threads that attempt to access the database. In previous
versions of Asterisk, this was tolerable, because the most used channel
driver, chan_sip, mostly accessed the database from a single thread.
With PJSIP, however, many threads may be attempting to perform database
operations, and there is the potential for many more database accesses,
meaning the concurrency is a horrible bottleneck if only one connection
is shared.
Asterisk has a connection pooling facility built into it, but the
implementation has flaws. For one, there is a strict limit on the number
of simultaneous connections that could be made to the database. Anything
beyond the maximum would result in a failed operation. Attempting to
predict what the maximum should be is nearly impossible even for someone
intimately familiar with Asterisk's threading model. In addition, use of
transactions in the dialplan can cause some severe bugs if connection
pooling is enabled.
This commit seeks to fix the concurrency problem by removing all
connection management code from Asterisk and leaving that to the
underlying unixODBC code instead. Now, Asterisk does not share a single
connection, nor does it try to maintain a connection pool. Instead, all
Asterisk ever does is request a connection from unixODBC and allow
unixODBC to either allocate those connections or retrieve them from a
pool.
Doing this has a bit of a ripple effect. For one, since connections are
not long-lived objects, several of the safeguards that previously
existed have been removed. We don't have to worry about trying to use a
connection that has gone stale. In every case, when we request a
connection, it has just been made and we don't need to perform any
sanity checks to be sure it's still active.
Another major player affected by this change is transactions.
Transactions and their respective connections were so tightly coupled
that it was almost pornographic. This code change moves
transaction-related code to its own file separate from the core ODBC
functionality. This way, the core of ODBC does not even have to know
that transactions exist.
In making this large change, I had to look at a lot of code and
understand it. When making this change, I discovered several places
where the behavior is definitely not ideal, but it seemed outside the
scope of this change to be fixing it. Instead, any place where I saw
some sort of room for improvement has had a XXX comment added explaining
what could be altered to improve it.
Change-Id: I37a84def5ea4ddf93868ce8105f39de078297fbf
											 
										 
										
											2015-12-23 15:07:05 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										ast_debug ( 3 ,  " res_odbc: Connected to %s [%s (%p)] \n " ,  obj - > parent - > name ,  obj - > parent - > dsn ,  obj ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2004-07-08 19:58:26 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2004-06-11 00:12:35 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2012-02-27 15:35:10 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									obj - > con  =  con ; 
							 
						 
					
						
							
								
									
										
										
										
											2004-07-08 19:58:26 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									return  ODBC_SUCCESS ; 
							 
						 
					
						
							
								
									
										
										
										
											2004-06-11 00:12:35 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2010-07-08 14:48:42 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								/*!
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  \ internal 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  \ brief  Implements  the  channels  provider . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  int  data_odbc_provider_handler ( const  struct  ast_data_search  * search ,  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										struct  ast_data  * root ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
									
										
											 
										
											
												res_odbc: Remove connection management
Asterisk by default will create a single database connection and share
it among all threads that attempt to access the database. In previous
versions of Asterisk, this was tolerable, because the most used channel
driver, chan_sip, mostly accessed the database from a single thread.
With PJSIP, however, many threads may be attempting to perform database
operations, and there is the potential for many more database accesses,
meaning the concurrency is a horrible bottleneck if only one connection
is shared.
Asterisk has a connection pooling facility built into it, but the
implementation has flaws. For one, there is a strict limit on the number
of simultaneous connections that could be made to the database. Anything
beyond the maximum would result in a failed operation. Attempting to
predict what the maximum should be is nearly impossible even for someone
intimately familiar with Asterisk's threading model. In addition, use of
transactions in the dialplan can cause some severe bugs if connection
pooling is enabled.
This commit seeks to fix the concurrency problem by removing all
connection management code from Asterisk and leaving that to the
underlying unixODBC code instead. Now, Asterisk does not share a single
connection, nor does it try to maintain a connection pool. Instead, all
Asterisk ever does is request a connection from unixODBC and allow
unixODBC to either allocate those connections or retrieve them from a
pool.
Doing this has a bit of a ripple effect. For one, since connections are
not long-lived objects, several of the safeguards that previously
existed have been removed. We don't have to worry about trying to use a
connection that has gone stale. In every case, when we request a
connection, it has just been made and we don't need to perform any
sanity checks to be sure it's still active.
Another major player affected by this change is transactions.
Transactions and their respective connections were so tightly coupled
that it was almost pornographic. This code change moves
transaction-related code to its own file separate from the core ODBC
functionality. This way, the core of ODBC does not even have to know
that transactions exist.
In making this large change, I had to look at a lot of code and
understand it. When making this change, I discovered several places
where the behavior is definitely not ideal, but it seemed outside the
scope of this change to be fixing it. Instead, any place where I saw
some sort of room for improvement has had a XXX comment added explaining
what could be altered to improve it.
Change-Id: I37a84def5ea4ddf93868ce8105f39de078297fbf
											 
										 
										
											2015-12-23 15:07:05 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									struct  ao2_iterator  aoi ; 
							 
						 
					
						
							
								
									
										
										
										
											2010-07-08 14:48:42 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									struct  odbc_class  * class ; 
							 
						 
					
						
							
								
									
										
											 
										
											
												res_odbc: Remove connection management
Asterisk by default will create a single database connection and share
it among all threads that attempt to access the database. In previous
versions of Asterisk, this was tolerable, because the most used channel
driver, chan_sip, mostly accessed the database from a single thread.
With PJSIP, however, many threads may be attempting to perform database
operations, and there is the potential for many more database accesses,
meaning the concurrency is a horrible bottleneck if only one connection
is shared.
Asterisk has a connection pooling facility built into it, but the
implementation has flaws. For one, there is a strict limit on the number
of simultaneous connections that could be made to the database. Anything
beyond the maximum would result in a failed operation. Attempting to
predict what the maximum should be is nearly impossible even for someone
intimately familiar with Asterisk's threading model. In addition, use of
transactions in the dialplan can cause some severe bugs if connection
pooling is enabled.
This commit seeks to fix the concurrency problem by removing all
connection management code from Asterisk and leaving that to the
underlying unixODBC code instead. Now, Asterisk does not share a single
connection, nor does it try to maintain a connection pool. Instead, all
Asterisk ever does is request a connection from unixODBC and allow
unixODBC to either allocate those connections or retrieve them from a
pool.
Doing this has a bit of a ripple effect. For one, since connections are
not long-lived objects, several of the safeguards that previously
existed have been removed. We don't have to worry about trying to use a
connection that has gone stale. In every case, when we request a
connection, it has just been made and we don't need to perform any
sanity checks to be sure it's still active.
Another major player affected by this change is transactions.
Transactions and their respective connections were so tightly coupled
that it was almost pornographic. This code change moves
transaction-related code to its own file separate from the core ODBC
functionality. This way, the core of ODBC does not even have to know
that transactions exist.
In making this large change, I had to look at a lot of code and
understand it. When making this change, I discovered several places
where the behavior is definitely not ideal, but it seemed outside the
scope of this change to be fixing it. Instead, any place where I saw
some sort of room for improvement has had a XXX comment added explaining
what could be altered to improve it.
Change-Id: I37a84def5ea4ddf93868ce8105f39de078297fbf
											 
										 
										
											2015-12-23 15:07:05 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									struct  ast_data  * data_odbc_class ,  * data_odbc_connections ; 
							 
						 
					
						
							
								
									
										
										
										
											2010-07-08 14:48:42 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									struct  ast_data  * enum_node ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									aoi  =  ao2_iterator_init ( class_container ,  0 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									while  ( ( class  =  ao2_iterator_next ( & aoi ) ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										data_odbc_class  =  ast_data_add_node ( root ,  " class " ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ( ! data_odbc_class )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ao2_ref ( class ,  - 1 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											continue ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_data_add_structure ( odbc_class ,  data_odbc_class ,  class ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										data_odbc_connections  =  ast_data_add_node ( data_odbc_class ,  " connections " ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ( ! data_odbc_connections )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ao2_ref ( class ,  - 1 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											continue ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										/* isolation */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										enum_node  =  ast_data_add_node ( data_odbc_class ,  " isolation " ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ( ! enum_node )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ao2_ref ( class ,  - 1 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											continue ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_data_add_int ( enum_node ,  " value " ,  class - > isolation ) ; 
							 
						 
					
						
							
								
									
										
											 
										
											
												res_odbc: Remove connection management
Asterisk by default will create a single database connection and share
it among all threads that attempt to access the database. In previous
versions of Asterisk, this was tolerable, because the most used channel
driver, chan_sip, mostly accessed the database from a single thread.
With PJSIP, however, many threads may be attempting to perform database
operations, and there is the potential for many more database accesses,
meaning the concurrency is a horrible bottleneck if only one connection
is shared.
Asterisk has a connection pooling facility built into it, but the
implementation has flaws. For one, there is a strict limit on the number
of simultaneous connections that could be made to the database. Anything
beyond the maximum would result in a failed operation. Attempting to
predict what the maximum should be is nearly impossible even for someone
intimately familiar with Asterisk's threading model. In addition, use of
transactions in the dialplan can cause some severe bugs if connection
pooling is enabled.
This commit seeks to fix the concurrency problem by removing all
connection management code from Asterisk and leaving that to the
underlying unixODBC code instead. Now, Asterisk does not share a single
connection, nor does it try to maintain a connection pool. Instead, all
Asterisk ever does is request a connection from unixODBC and allow
unixODBC to either allocate those connections or retrieve them from a
pool.
Doing this has a bit of a ripple effect. For one, since connections are
not long-lived objects, several of the safeguards that previously
existed have been removed. We don't have to worry about trying to use a
connection that has gone stale. In every case, when we request a
connection, it has just been made and we don't need to perform any
sanity checks to be sure it's still active.
Another major player affected by this change is transactions.
Transactions and their respective connections were so tightly coupled
that it was almost pornographic. This code change moves
transaction-related code to its own file separate from the core ODBC
functionality. This way, the core of ODBC does not even have to know
that transactions exist.
In making this large change, I had to look at a lot of code and
understand it. When making this change, I discovered several places
where the behavior is definitely not ideal, but it seemed outside the
scope of this change to be fixing it. Instead, any place where I saw
some sort of room for improvement has had a XXX comment added explaining
what could be altered to improve it.
Change-Id: I37a84def5ea4ddf93868ce8105f39de078297fbf
											 
										 
										
											2015-12-23 15:07:05 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										ast_data_add_str ( enum_node ,  " text " ,  ast_odbc_isolation2text ( class - > isolation ) ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2010-07-08 14:48:42 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										ao2_ref ( class ,  - 1 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ( ! ast_data_search_match ( search ,  data_odbc_class ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ast_data_remove_node ( root ,  data_odbc_class ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2012-01-27 18:47:16 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									ao2_iterator_destroy ( & aoi ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2010-07-08 14:48:42 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									return  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								/*!
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  \ internal 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  \ brief  / asterisk / res / odbc / listprovider . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  const  struct  ast_data_handler  odbc_provider  =  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									. version  =  AST_DATA_HANDLER_VERSION , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									. get  =  data_odbc_provider_handler 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								} ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  const  struct  ast_data_entry  odbc_providers [ ]  =  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									AST_DATA_ENTRY ( " /asterisk/res/odbc " ,  & odbc_provider ) , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								} ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2006-08-21 02:11:39 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								static  int  reload ( void )  
						 
					
						
							
								
									
										
										
										
											2004-07-08 19:58:26 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
									
										
										
										
											2008-06-10 21:14:58 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									struct  odbc_cache_tables  * table ; 
							 
						 
					
						
							
								
									
										
										
										
											2008-05-05 23:38:15 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									struct  odbc_class  * class ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									struct  ao2_iterator  aoi  =  ao2_iterator_init ( class_container ,  0 ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2006-04-18 18:16:32 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/* First, mark all to be purged */ 
							 
						 
					
						
							
								
									
										
										
										
											2008-05-05 23:38:15 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									while  ( ( class  =  ao2_iterator_next ( & aoi ) ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2006-04-18 18:16:32 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										class - > delme  =  1 ; 
							 
						 
					
						
							
								
									
										
										
										
											2008-05-05 23:38:15 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										ao2_ref ( class ,  - 1 ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2006-04-18 18:16:32 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2009-10-06 01:24:24 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									ao2_iterator_destroy ( & aoi ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2006-04-18 18:16:32 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2008-05-05 23:38:15 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									load_odbc_config ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2006-04-18 18:16:32 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2008-05-20 16:13:48 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									aoi  =  ao2_iterator_init ( class_container ,  0 ) ; 
							 
						 
					
						
							
								
									
										
											 
										
											
												res_odbc: Remove connection management
Asterisk by default will create a single database connection and share
it among all threads that attempt to access the database. In previous
versions of Asterisk, this was tolerable, because the most used channel
driver, chan_sip, mostly accessed the database from a single thread.
With PJSIP, however, many threads may be attempting to perform database
operations, and there is the potential for many more database accesses,
meaning the concurrency is a horrible bottleneck if only one connection
is shared.
Asterisk has a connection pooling facility built into it, but the
implementation has flaws. For one, there is a strict limit on the number
of simultaneous connections that could be made to the database. Anything
beyond the maximum would result in a failed operation. Attempting to
predict what the maximum should be is nearly impossible even for someone
intimately familiar with Asterisk's threading model. In addition, use of
transactions in the dialplan can cause some severe bugs if connection
pooling is enabled.
This commit seeks to fix the concurrency problem by removing all
connection management code from Asterisk and leaving that to the
underlying unixODBC code instead. Now, Asterisk does not share a single
connection, nor does it try to maintain a connection pool. Instead, all
Asterisk ever does is request a connection from unixODBC and allow
unixODBC to either allocate those connections or retrieve them from a
pool.
Doing this has a bit of a ripple effect. For one, since connections are
not long-lived objects, several of the safeguards that previously
existed have been removed. We don't have to worry about trying to use a
connection that has gone stale. In every case, when we request a
connection, it has just been made and we don't need to perform any
sanity checks to be sure it's still active.
Another major player affected by this change is transactions.
Transactions and their respective connections were so tightly coupled
that it was almost pornographic. This code change moves
transaction-related code to its own file separate from the core ODBC
functionality. This way, the core of ODBC does not even have to know
that transactions exist.
In making this large change, I had to look at a lot of code and
understand it. When making this change, I discovered several places
where the behavior is definitely not ideal, but it seemed outside the
scope of this change to be fixing it. Instead, any place where I saw
some sort of room for improvement has had a XXX comment added explaining
what could be altered to improve it.
Change-Id: I37a84def5ea4ddf93868ce8105f39de078297fbf
											 
										 
										
											2015-12-23 15:07:05 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									while  ( ( class  =  ao2_iterator_next ( & aoi ) ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2008-05-20 16:13:48 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  ( class - > delme )  { 
							 
						 
					
						
							
								
									
										
											 
										
											
												res_odbc: Remove connection management
Asterisk by default will create a single database connection and share
it among all threads that attempt to access the database. In previous
versions of Asterisk, this was tolerable, because the most used channel
driver, chan_sip, mostly accessed the database from a single thread.
With PJSIP, however, many threads may be attempting to perform database
operations, and there is the potential for many more database accesses,
meaning the concurrency is a horrible bottleneck if only one connection
is shared.
Asterisk has a connection pooling facility built into it, but the
implementation has flaws. For one, there is a strict limit on the number
of simultaneous connections that could be made to the database. Anything
beyond the maximum would result in a failed operation. Attempting to
predict what the maximum should be is nearly impossible even for someone
intimately familiar with Asterisk's threading model. In addition, use of
transactions in the dialplan can cause some severe bugs if connection
pooling is enabled.
This commit seeks to fix the concurrency problem by removing all
connection management code from Asterisk and leaving that to the
underlying unixODBC code instead. Now, Asterisk does not share a single
connection, nor does it try to maintain a connection pool. Instead, all
Asterisk ever does is request a connection from unixODBC and allow
unixODBC to either allocate those connections or retrieve them from a
pool.
Doing this has a bit of a ripple effect. For one, since connections are
not long-lived objects, several of the safeguards that previously
existed have been removed. We don't have to worry about trying to use a
connection that has gone stale. In every case, when we request a
connection, it has just been made and we don't need to perform any
sanity checks to be sure it's still active.
Another major player affected by this change is transactions.
Transactions and their respective connections were so tightly coupled
that it was almost pornographic. This code change moves
transaction-related code to its own file separate from the core ODBC
functionality. This way, the core of ODBC does not even have to know
that transactions exist.
In making this large change, I had to look at a lot of code and
understand it. When making this change, I discovered several places
where the behavior is definitely not ideal, but it seemed outside the
scope of this change to be fixing it. Instead, any place where I saw
some sort of room for improvement has had a XXX comment added explaining
what could be altered to improve it.
Change-Id: I37a84def5ea4ddf93868ce8105f39de078297fbf
											 
										 
										
											2015-12-23 15:07:05 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											ao2_unlink ( class_container ,  class ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2008-05-20 16:13:48 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
											 
										
											
												res_odbc: Remove connection management
Asterisk by default will create a single database connection and share
it among all threads that attempt to access the database. In previous
versions of Asterisk, this was tolerable, because the most used channel
driver, chan_sip, mostly accessed the database from a single thread.
With PJSIP, however, many threads may be attempting to perform database
operations, and there is the potential for many more database accesses,
meaning the concurrency is a horrible bottleneck if only one connection
is shared.
Asterisk has a connection pooling facility built into it, but the
implementation has flaws. For one, there is a strict limit on the number
of simultaneous connections that could be made to the database. Anything
beyond the maximum would result in a failed operation. Attempting to
predict what the maximum should be is nearly impossible even for someone
intimately familiar with Asterisk's threading model. In addition, use of
transactions in the dialplan can cause some severe bugs if connection
pooling is enabled.
This commit seeks to fix the concurrency problem by removing all
connection management code from Asterisk and leaving that to the
underlying unixODBC code instead. Now, Asterisk does not share a single
connection, nor does it try to maintain a connection pool. Instead, all
Asterisk ever does is request a connection from unixODBC and allow
unixODBC to either allocate those connections or retrieve them from a
pool.
Doing this has a bit of a ripple effect. For one, since connections are
not long-lived objects, several of the safeguards that previously
existed have been removed. We don't have to worry about trying to use a
connection that has gone stale. In every case, when we request a
connection, it has just been made and we don't need to perform any
sanity checks to be sure it's still active.
Another major player affected by this change is transactions.
Transactions and their respective connections were so tightly coupled
that it was almost pornographic. This code change moves
transaction-related code to its own file separate from the core ODBC
functionality. This way, the core of ODBC does not even have to know
that transactions exist.
In making this large change, I had to look at a lot of code and
understand it. When making this change, I discovered several places
where the behavior is definitely not ideal, but it seemed outside the
scope of this change to be fixing it. Instead, any place where I saw
some sort of room for improvement has had a XXX comment added explaining
what could be altered to improve it.
Change-Id: I37a84def5ea4ddf93868ce8105f39de078297fbf
											 
										 
										
											2015-12-23 15:07:05 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										ao2_ref ( class ,  - 1 ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2008-05-20 16:13:48 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2009-10-06 01:24:24 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									ao2_iterator_destroy ( & aoi ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2006-04-18 18:16:32 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2008-06-10 21:14:58 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									/* Empty the cache; it will get rebuilt the next time the tables are needed. */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									AST_RWLIST_WRLOCK ( & odbc_tables ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									while  ( ( table  =  AST_RWLIST_REMOVE_HEAD ( & odbc_tables ,  list ) ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										destroy_table_cache ( table ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									AST_RWLIST_UNLOCK ( & odbc_tables ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2004-07-08 19:58:26 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									return  0 ; 
							 
						 
					
						
							
								
									
										
										
										
											2004-06-11 00:12:35 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2006-08-21 02:11:39 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								static  int  unload_module ( void )  
						 
					
						
							
								
									
										
										
										
											2006-04-18 18:16:32 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/* Prohibit unloading */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  - 1 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2012-10-01 23:24:10 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								/*!
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  \ brief  Load  the  module 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 * 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  Module  loading  including  tests  for  configuration  or  dependencies . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  This  function  can  return  AST_MODULE_LOAD_FAILURE ,  AST_MODULE_LOAD_DECLINE , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  or  AST_MODULE_LOAD_SUCCESS .  If  a  dependency  or  environment  variable  fails 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  tests  return  AST_MODULE_LOAD_FAILURE .  If  the  module  can  not  load  the  
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  configuration  file  or  other  non - critical  problem  return  
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  AST_MODULE_LOAD_DECLINE .  On  success  return  AST_MODULE_LOAD_SUCCESS . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 */ 
							 
						 
					
						
							
								
									
										
										
										
											2006-08-21 02:11:39 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								static  int  load_module ( void )  
						 
					
						
							
								
									
										
										
										
											2004-07-08 19:58:26 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
									
										
										
										
											2008-05-05 23:38:15 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  ( ! ( class_container  =  ao2_container_alloc ( 1 ,  null_hash_fn ,  ao2_match_by_addr ) ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  AST_MODULE_LOAD_DECLINE ; 
							 
						 
					
						
							
								
									
										
										
										
											2008-01-18 06:52:18 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  ( load_odbc_config ( )  = =  - 1 ) 
							 
						 
					
						
							
								
									
										
										
										
											2006-08-31 21:00:20 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										return  AST_MODULE_LOAD_DECLINE ; 
							 
						 
					
						
							
								
									
										
										
										
											2008-12-05 10:31:25 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									ast_cli_register_multiple ( cli_odbc ,  ARRAY_LEN ( cli_odbc ) ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2010-07-08 14:48:42 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									ast_data_register_multiple ( odbc_providers ,  ARRAY_LEN ( odbc_providers ) ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2004-07-08 19:58:26 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									ast_log ( LOG_NOTICE ,  " res_odbc loaded. \n " ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
									
										
										
										
											2004-06-11 00:12:35 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2010-07-20 19:35:02 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								AST_MODULE_INFO ( ASTERISK_GPL_KEY ,  AST_MODFLAG_GLOBAL_SYMBOLS  |  AST_MODFLAG_LOAD_ORDER ,  " ODBC resource " ,  
						 
					
						
							
								
									
										
										
										
											2015-05-05 20:49:04 -04:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									. support_level  =  AST_MODULE_SUPPORT_CORE , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									. load  =  load_module , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									. unload  =  unload_module , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									. reload  =  reload , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									. load_pri  =  AST_MODPRI_REALTIME_DEPEND , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								) ;