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 
							 
						 
					
						
							
								
									
										
										
										
											2017-12-22 09:23:22 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								 * 
							 
						 
					
						
							
								
									
										
										
										
											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 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								 * 
							 
						 
					
						
							
								
									
										
										
										
											2021-11-17 10:24:54 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								 *  \ arg  See  also :  \ ref  cdr_odbc . c 
							 
						 
					
						
							
								
									
										
										
										
											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 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2017-12-22 09:23:22 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								/*!
  
						 
					
						
							
								
									
										
										
										
											2012-10-01 23:24:10 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								 *  \ 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 > 
							 
						 
					
						
							
								
									
										
										
										
											2016-08-18 14:15:46 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									< depend > res_odbc_transaction < / 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" 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											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" 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											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 */ 
							 
						 
					
						
							
								
									
										
										
										
											2016-06-02 14:04:45 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									unsigned  int  maxconnections ;          /*!< Maximum number of allowed connections */ 
							 
						 
					
						
							
								
									
										
										
										
											2010-07-23 16:19:21 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									/*! 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 ; 
							 
						 
					
						
							
								
									
										
										
										
											2016-06-02 14:04:45 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									/*! A pool of available connections */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									AST_LIST_HEAD_NOLOCK ( ,  odbc_obj )  connections ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/*! Lock to protect the connections */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ast_mutex_t  lock ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/*! Condition to notify any pending connection requesters */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ast_cond_t  cond ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/*! The total number of current connections */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									size_t  connection_cnt ; 
							 
						 
					
						
							
								
									
										
										
										
											2019-02-06 12:16:01 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									/*! Whether logging is enabled on this class or not */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									unsigned  int  logging ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/*! The number of prepares executed on this class (total from all connections */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									int  prepares_executed ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/*! The number of queries executed on this class (total from all connections) */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									int  queries_executed ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/*! The longest execution time for a query executed on this class */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									long  longest_query_execution_time ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/*! The SQL query that took the longest to execute */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									char  * sql_text ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/*! Slow query limit (in milliseconds) */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									unsigned  int  slowquerylimit ; 
							 
						 
					
						
							
								
									
										
										
										
											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 ) ;  
						 
					
						
							
								
									
										
										
										
											2016-06-02 14:04:45 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								static  void  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 */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								} ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
											 
										
											
												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 ; 
							 
						 
					
						
							
								
									
										
										
										
											2016-06-02 14:04:45 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									struct  odbc_obj  * obj ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2008-05-05 23:38:15 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									/* 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 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2016-06-02 14:04:45 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									while  ( ( obj  =  AST_LIST_REMOVE_HEAD ( & class - > connections ,  list ) ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ao2_ref ( obj ,  - 1 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2008-05-05 23:38:15 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									SQLFreeHandle ( SQL_HANDLE_ENV ,  class - > env ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2016-06-02 14:04:45 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									ast_mutex_destroy ( & class - > lock ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ast_cond_destroy ( & class - > cond ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2019-02-06 12:16:01 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									ast_free ( class - > sql_text ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2008-05-05 23:38:15 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  void  odbc_obj_destructor ( void  * data )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									struct  odbc_obj  * obj  =  data ; 
							 
						 
					
						
							
								
									
										
										
										
											2016-06-02 14:04:45 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2008-05-05 23:38:15 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									odbc_obj_disconnect ( obj ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
									
										
										
										
											2004-06-11 00:12:35 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2016-06-02 14:04:45 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								static  void  destroy_table_cache ( struct  odbc_cache_tables  * table )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
									
										
										
										
											2008-06-10 21:14:58 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									struct  odbc_cache_columns  * col ; 
							 
						 
					
						
							
								
									
										
										
										
											2016-06-02 14:04:45 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2008-06-10 21:14:58 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									ast_debug ( 1 ,  " Destroying table cache for %s \n " ,  table - > table ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2016-06-02 14:04:45 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2008-06-10 21:14:58 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									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 ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2016-06-02 14:04:45 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2008-06-10 21:14:58 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									ast_free ( table ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								/*!
  
						 
					
						
							
								
									
										
											 
										
											
												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 . 
							 
						 
					
						
							
								
									
										
										
										
											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 )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
									
										
										
										
											2019-02-06 12:16:01 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									struct  timeval  start ; 
							 
						 
					
						
							
								
									
										
										
										
											2007-09-14 17:29:23 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									SQLHSTMT  stmt ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2019-02-06 12:16:01 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  ( obj - > parent - > logging )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										start  =  ast_tvnow ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
											 
										
											
												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 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2019-02-06 12:16:01 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  ( obj - > parent - > logging )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										long  execution_time  =  ast_tvdiff_ms ( ast_tvnow ( ) ,  start ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ( obj - > parent - > slowquerylimit  & &  execution_time  >  obj - > parent - > slowquerylimit )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ast_log ( LOG_WARNING ,  " SQL query '%s' took %ld milliseconds to execute on class '%s', this may indicate a database problem \n " , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												obj - > sql_text ,  execution_time ,  obj - > parent - > name ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_mutex_lock ( & obj - > parent - > lock ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ( execution_time  >  obj - > parent - > longest_query_execution_time  | |  ! obj - > parent - > sql_text )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											obj - > parent - > longest_query_execution_time  =  execution_time ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											/* Due to the callback nature of the res_odbc API it's not possible to ensure that
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											 *  the  SQL  text  is  removed  from  the  connection  in  all  cases ,  so  only  if  it  becomes  the 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											 *  new  longest  executing  query  do  we  steal  the  SQL  text .  In  other  cases  what  will  happen 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											 *  is  that  the  SQL  text  will  be  freed  if  the  connection  is  released  back  to  the  class  or 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											 *  if  a  new  query  is  done  on  the  connection . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											 */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ast_free ( obj - > parent - > sql_text ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											obj - > parent - > sql_text  =  obj - > sql_text ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											obj - > sql_text  =  NULL ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_mutex_unlock ( & obj - > parent - > lock ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											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 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
									
										
										
										
											2019-02-06 12:16:01 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									struct  timeval  start ; 
							 
						 
					
						
							
								
									
										
											 
										
											
												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 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2019-02-06 12:16:01 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  ( obj - > parent - > logging )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										start  =  ast_tvnow ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
											 
										
											
												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 ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2016-06-02 14:04:45 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  ( ! stmt )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  NULL ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2005-11-09 02:01:12 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2016-06-02 14:04:45 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									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 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2016-06-02 14:04:45 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_log ( LOG_WARNING ,  " SQL Execute error %d! \n " ,  res ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										SQLFreeHandle ( SQL_HANDLE_STMT ,  stmt ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										stmt  =  NULL ; 
							 
						 
					
						
							
								
									
										
										
										
											2019-02-06 12:16:01 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									}  else  if  ( obj - > parent - > logging )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										long  execution_time  =  ast_tvdiff_ms ( ast_tvnow ( ) ,  start ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ( obj - > parent - > slowquerylimit  & &  execution_time  >  obj - > parent - > slowquerylimit )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ast_log ( LOG_WARNING ,  " SQL query '%s' took %ld milliseconds to execute on class '%s', this may indicate a database problem \n " , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												obj - > sql_text ,  execution_time ,  obj - > parent - > name ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_mutex_lock ( & obj - > parent - > lock ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										/* If this takes the record on longest query execution time, update the parent class
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 *  with  the  information . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ( execution_time  >  obj - > parent - > longest_query_execution_time  | |  ! obj - > parent - > sql_text )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											obj - > parent - > longest_query_execution_time  =  execution_time ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ast_free ( obj - > parent - > sql_text ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											obj - > parent - > sql_text  =  obj - > sql_text ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											obj - > sql_text  =  NULL ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_mutex_unlock ( & obj - > parent - > lock ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_atomic_fetchadd_int ( & obj - > parent - > queries_executed ,  + 1 ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2005-11-09 02:01:12 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  stmt ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2019-02-06 12:16:01 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								int  ast_odbc_prepare ( struct  odbc_obj  * obj ,  SQLHSTMT  * stmt ,  const  char  * sql )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( obj - > parent - > logging )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										/* It is possible for this connection to be reused without being
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 *  released  back  to  the  class ,  so  we  free  what  may  already  exist 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 *  and  place  the  new  SQL  in . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										 */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_free ( obj - > sql_text ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										obj - > sql_text  =  ast_strdup ( sql ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_atomic_fetchadd_int ( & obj - > parent - > prepares_executed ,  + 1 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  SQLPrepare ( stmt ,  ( unsigned  char  * ) sql ,  SQL_NTS ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								SQLRETURN  ast_odbc_execute_sql ( struct  odbc_obj  * obj ,  SQLHSTMT  * stmt ,  const  char  * sql )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( obj - > parent - > logging )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_free ( obj - > sql_text ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										obj - > sql_text  =  ast_strdup ( sql ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_atomic_fetchadd_int ( & obj - > parent - > queries_executed ,  + 1 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  SQLExecDirect ( stmt ,  ( unsigned  char  * ) sql ,  SQL_NTS ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											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 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2019-02-06 12:16:01 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  ( obj - > parent - > logging )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_atomic_fetchadd_int ( & obj - > parent - > queries_executed ,  + 1 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											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 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									SQLSMALLINT  diagbytes  =  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									SQLSMALLINT  i ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									unsigned  char  state [ 10 ] ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									unsigned  char  diagnostic [ 256 ] ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ast_str_reset ( errors ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2018-09-20 14:59:54 -04:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									i  =  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									while  ( SQLGetDiagRec ( handle_type ,  handle ,  + + i ,  state ,  & nativeerror , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										diagnostic ,  sizeof ( diagnostic ) ,  & diagbytes )  = =  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_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 )  { 
							 
						 
					
						
							
								
									
										
										
										
											2018-09-20 14:59:54 -04:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											ast_log ( LOG_WARNING ,  " There are more than 10 diagnostic records! Ignore the rest. \n " ) ; 
							 
						 
					
						
							
								
									
										
											 
										
											
												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 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											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 ; 
							 
						 
					
						
							
								
									
										
										
										
											2019-02-06 12:16:01 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									int  enabled ,  bse ,  conntimeout ,  forcecommit ,  isolation ,  maxconnections ,  logging ,  slowquerylimit ; 
							 
						 
					
						
							
								
									
										
										
										
											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 ; 
							 
						 
					
						
							
								
									
										
										
										
											2016-06-02 14:04:45 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											maxconnections  =  1 ; 
							 
						 
					
						
							
								
									
										
										
										
											2019-02-06 12:16:01 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											logging  =  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											slowquerylimit  =  5000 ; 
							 
						 
					
						
							
								
									
										
										
										
											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-09-21 15:48:47 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
													ast_log ( LOG_WARNING ,  " The 'pooling', 'shared_connections', 'limit', and 'idlecheck' options were replaced by 'max_connections'.  See res_odbc.conf.sample. \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 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													} 
							 
						 
					
						
							
								
									
										
										
										
											2016-06-02 14:04:45 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												}  else  if  ( ! strcasecmp ( v - > name ,  " max_connections " ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													if  ( sscanf ( v - > value ,  " %30d " ,  & maxconnections )  ! =  1  | |  maxconnections  <  1 )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
														ast_log ( LOG_WARNING ,  " max_connections must be a positive integer \n " ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
														maxconnections  =  1 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                                        } 
							 
						 
					
						
							
								
									
										
										
										
											2019-02-06 12:16:01 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												}  else  if  ( ! strcasecmp ( v - > name ,  " logging " ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													logging  =  ast_true ( v - > value ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												}  else  if  ( ! strcasecmp ( v - > name ,  " slow_query_limit " ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													if  ( sscanf ( v - > value ,  " %30d " ,  & slowquerylimit )  ! =  1 )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
														ast_log ( LOG_WARNING ,  " slow_query_limit must be a positive integer \n " ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
														slowquerylimit  =  5000 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													} 
							 
						 
					
						
							
								
									
										
										
										
											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 ; 
							 
						 
					
						
							
								
									
										
										
										
											2016-06-02 14:04:45 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												new - > maxconnections  =  maxconnections ; 
							 
						 
					
						
							
								
									
										
										
										
											2019-02-06 12:16:01 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												new - > logging  =  logging ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												new - > slowquerylimit  =  slowquerylimit ; 
							 
						 
					
						
							
								
									
										
										
										
											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 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2016-06-02 14:04:45 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												ast_mutex_init ( & new - > lock ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												ast_cond_init ( & new - > cond ,  NULL ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											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 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2007-09-18 22:43:45 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											ast_cli ( a - > fd ,  "   Name:   %s \n   DSN:    %s \n " ,  class - > name ,  class - > dsn ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2016-08-06 02:37:35 -04:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  ( class - > last_negative_connect . tv_sec  >  0 )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												ast_localtime ( & class - > last_negative_connect ,  & tm ,  NULL ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												ast_strftime ( timestr ,  sizeof ( timestr ) ,  " %Y-%m-%d %T " ,  & tm ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												ast_cli ( a - > fd ,  "     Last fail connection attempt: %s \n " ,  timestr ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2016-06-02 14:04:45 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											ast_cli ( a - > fd ,  "     Number of active connections: %zd (out of %d) \n " ,  class - > connection_cnt ,  class - > maxconnections ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2019-02-06 12:16:01 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											ast_cli ( a - > fd ,  "     Logging: %s \n " ,  class - > logging  ?  " Enabled "  :  " Disabled " ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  ( class - > logging )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												ast_cli ( a - > fd ,  "     Number of prepares executed: %d \n " ,  class - > prepares_executed ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												ast_cli ( a - > fd ,  "     Number of queries executed: %d \n " ,  class - > queries_executed ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												ast_mutex_lock ( & class - > lock ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												if  ( class - > sql_text )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													ast_cli ( a - > fd ,  "     Longest running SQL query: %s (%ld milliseconds) \n " ,  class - > sql_text ,  class - > longest_query_execution_time ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												ast_mutex_unlock ( & class - > lock ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
									
										
										
										
											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 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2016-06-02 14:04:45 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								static  void  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 ; 
							 
						 
					
						
							
								
									
										
										
										
											2004-06-11 00:12:35 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2016-06-02 14:04:45 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									ao2_link ( class_container ,  class ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/* I still have a reference in the caller, so a deref is NOT missing here. */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( ! preconnect )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return ; 
							 
						 
					
						
							
								
									
										
										
										
											2005-02-17 16:31:08 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2016-06-02 14:04:45 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/* Request and release builds a connection */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									obj  =  ast_odbc_request_obj ( class - > name ,  0 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( obj )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_odbc_release_obj ( obj ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return ; 
							 
						 
					
						
							
								
									
										
										
										
											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 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
									
										
										
										
											2016-06-02 14:04:45 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									struct  odbc_class  * class  =  obj - > parent ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ast_debug ( 2 ,  " Releasing ODBC handle %p into pool \n " ,  obj ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/* The odbc_obj only holds a reference to the class when it is
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 *  actively  being  used .  This  guarantees  no  circular  reference 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 *  between  odbc_class  and  odbc_obj .  Since  it  is  being  released 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 *  we  also  release  our  class  reference .  If  a  reload  occurred  before 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 *  the  class  will  go  away  automatically  once  all  odbc_obj  are 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 *  released  back . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									obj - > parent  =  NULL ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2019-02-06 12:16:01 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									/* Free the SQL text so that the next user of this connection has
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 *  a  fresh  start . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ast_free ( obj - > sql_text ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									obj - > sql_text  =  NULL ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2016-06-02 14:04:45 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									ast_mutex_lock ( & class - > lock ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									AST_LIST_INSERT_HEAD ( & class - > connections ,  obj ,  list ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ast_cond_signal ( & class - > cond ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ast_mutex_unlock ( & class - > lock ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ao2_ref ( class ,  - 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 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2016-07-10 21:08:28 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								unsigned  int  ast_odbc_get_max_connections ( const  char  * name )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									struct  odbc_class  * class ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									unsigned  int  max_connections ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									class  =  ao2_callback ( class_container ,  0 ,  aoro2_class_cb ,  ( char  * )  name ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( ! class )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									max_connections  =  class - > maxconnections ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ao2_ref ( class ,  - 1 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  max_connections ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-11-27 20:11:37 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								/*!
  
						 
					
						
							
								
									
										
										
										
											2016-06-02 14:04:45 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								 *  \ brief  Determine  if  the  connection  has  died . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 * 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  \ param  connection  The  connection  to  check 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  \ param  class  The  ODBC  class 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  \ retval  1  Yep ,  it ' s  dead 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  \ retval  0  It ' s  alive  and  well 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								static  int  connection_dead ( struct  odbc_obj  * connection ,  struct  odbc_class  * class )  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									char  * test_sql  =  " select 1 " ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									SQLINTEGER  dead ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									SQLRETURN  res ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									SQLHSTMT  stmt ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									res  =  SQLGetConnectAttr ( connection - > con ,  SQL_ATTR_CONNECTION_DEAD ,  & dead ,  0 ,  0 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( SQL_SUCCEEDED ( res ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  dead  = =  SQL_CD_TRUE  ?  1  :  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									/* If the Driver doesn't support SQL_ATTR_CONNECTION_DEAD do a
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 *  probing  query  instead 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									 */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									res  =  SQLAllocHandle ( SQL_HANDLE_STMT ,  connection - > con ,  & stmt ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( ! SQL_SUCCEEDED ( res ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  1 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( ! ast_strlen_zero ( class - > sanitysql ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										test_sql  =  class - > sanitysql ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									res  =  SQLPrepare ( stmt ,  ( unsigned  char  * ) test_sql ,  SQL_NTS ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( ! SQL_SUCCEEDED ( res ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										SQLFreeHandle ( SQL_HANDLE_STMT ,  stmt ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  1 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									res  =  SQLExecute ( stmt ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									SQLFreeHandle ( SQL_HANDLE_STMT ,  stmt ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  SQL_SUCCEEDED ( res )  ?  0  :  1 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2009-02-19 00:26:01 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								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 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2016-06-02 14:04:45 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									while  ( ! obj )  { 
							 
						 
					
						
							
								
									
										
										
										
											2023-11-30 11:57:53 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										ast_mutex_lock ( & class - > lock ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2016-06-02 14:04:45 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										obj  =  AST_LIST_REMOVE_HEAD ( & class - > connections ,  list ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-11-30 11:57:53 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										ast_mutex_unlock ( & class - > lock ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2016-06-02 14:04:45 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  ( ! obj )  { 
							 
						 
					
						
							
								
									
										
										
										
											2023-11-30 11:57:53 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											ast_mutex_lock ( & class - > lock ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2016-06-02 14:04:45 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											if  ( class - > connection_cnt  <  class - > maxconnections )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												/* If no connection is immediately available establish a new
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												 *  one  if  allowed .  If  we  try  and  fail  we  give  up  completely  as 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												 *  we  could  go  into  an  infinite  loop  otherwise . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												 */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												obj  =  ao2_alloc ( sizeof ( * obj ) ,  odbc_obj_destructor ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												if  ( ! obj )  { 
							 
						 
					
						
							
								
									
										
										
										
											2023-11-30 11:57:53 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
													ast_mutex_unlock ( & class - > lock ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2016-06-02 14:04:45 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
													break ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												obj - > parent  =  ao2_bump ( class ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-11-30 11:57:53 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												class - > connection_cnt + + ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												ast_mutex_unlock ( & class - > lock ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2016-06-02 14:04:45 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												if  ( odbc_obj_connect ( obj )  = =  ODBC_FAIL )  { 
							 
						 
					
						
							
								
									
										
										
										
											2023-11-30 11:57:53 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
													ast_mutex_lock ( & class - > lock ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													class - > connection_cnt - - ; 
							 
						 
					
						
							
								
									
										
											 
										
											
												res_odbc: release threads from potential starvation.
Whenever a slot is freed up due to a failed connection, wake up a waiter
before failing.
In the case of a dead connection there could be waiters, for example,
let's say two threads tries to acquire objects at the same time, with
one in the cached connections, one will acquire the dead connection, and
the other will enter into the wait state.  The thread with the dead
connection will clear up the dead connection, and then attempt a
re-acquire (at this point there cannot be cached connections else the
other thread would have received that and tried to clean up), as such,
at this point we're guaranteed that either there are no waiting threads,
or that the maxconnections - connection_cnt threads will attempt to
re-acquire connections, and then either succeed, using those
connections, or failing, and then signalling to release more waiters.
Also fix the pointer log for ODBC handle %p dead which would always
reflect NULL.
Signed-off-by: Jaco Kroon <jaco@uls.co.za>
(cherry picked from commit 9b45103bc815ccf74d1a4c3e1498bdfd4f8bbda8)
											 
										 
										
											2024-12-10 21:47:49 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
													ast_cond_signal ( & class - > cond ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-11-30 11:57:53 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
													ast_mutex_unlock ( & class - > lock ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2016-06-02 14:04:45 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
													ao2_ref ( obj - > parent ,  - 1 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													ao2_ref ( obj ,  - 1 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													obj  =  NULL ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													break ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-11-30 11:57:53 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												ast_mutex_lock ( & class - > lock ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2016-06-02 14:04:45 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												ast_debug ( 2 ,  " Created ODBC handle %p on class '%s', new count is %zd \n " ,  obj , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													name ,  class - > connection_cnt ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-11-30 11:57:53 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2016-06-02 14:04:45 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											}  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												/* Otherwise if we're not allowed to create a new one we
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												 *  wait  for  another  thread  to  give  up  the  connection  they 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												 *  own . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												 */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												ast_cond_wait ( & class - > cond ,  & class - > lock ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
									
										
										
										
											2023-11-30 11:57:53 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ast_mutex_unlock ( & class - > lock ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2016-06-02 14:04:45 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										}  else  if  ( connection_dead ( obj ,  class ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											/* If the connection is dead try to grab another functional one from the
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											 *  pool  instead  of  trying  to  resurrect  this  one . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											 */ 
							 
						 
					
						
							
								
									
										
										
										
											2023-11-30 11:57:53 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											ast_mutex_lock ( & class - > lock ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2016-06-02 14:04:45 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											class - > connection_cnt - - ; 
							 
						 
					
						
							
								
									
										
											 
										
											
												res_odbc: release threads from potential starvation.
Whenever a slot is freed up due to a failed connection, wake up a waiter
before failing.
In the case of a dead connection there could be waiters, for example,
let's say two threads tries to acquire objects at the same time, with
one in the cached connections, one will acquire the dead connection, and
the other will enter into the wait state.  The thread with the dead
connection will clear up the dead connection, and then attempt a
re-acquire (at this point there cannot be cached connections else the
other thread would have received that and tried to clean up), as such,
at this point we're guaranteed that either there are no waiting threads,
or that the maxconnections - connection_cnt threads will attempt to
re-acquire connections, and then either succeed, using those
connections, or failing, and then signalling to release more waiters.
Also fix the pointer log for ODBC handle %p dead which would always
reflect NULL.
Signed-off-by: Jaco Kroon <jaco@uls.co.za>
(cherry picked from commit 9b45103bc815ccf74d1a4c3e1498bdfd4f8bbda8)
											 
										 
										
											2024-12-10 21:47:49 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											/* this thread will re-acquire, and if that fails will signal,
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											 *  thus  no  need  to  signal  class - > cond  here  */ 
							 
						 
					
						
							
								
									
										
										
										
											2016-06-02 14:04:45 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											ast_debug ( 2 ,  " ODBC handle %p dead - removing from class '%s', new count is %zd \n " , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												obj ,  name ,  class - > connection_cnt ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2023-11-30 11:57:53 -06:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ast_mutex_unlock ( & class - > lock ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
											 
										
											
												res_odbc: release threads from potential starvation.
Whenever a slot is freed up due to a failed connection, wake up a waiter
before failing.
In the case of a dead connection there could be waiters, for example,
let's say two threads tries to acquire objects at the same time, with
one in the cached connections, one will acquire the dead connection, and
the other will enter into the wait state.  The thread with the dead
connection will clear up the dead connection, and then attempt a
re-acquire (at this point there cannot be cached connections else the
other thread would have received that and tried to clean up), as such,
at this point we're guaranteed that either there are no waiting threads,
or that the maxconnections - connection_cnt threads will attempt to
re-acquire connections, and then either succeed, using those
connections, or failing, and then signalling to release more waiters.
Also fix the pointer log for ODBC handle %p dead which would always
reflect NULL.
Signed-off-by: Jaco Kroon <jaco@uls.co.za>
(cherry picked from commit 9b45103bc815ccf74d1a4c3e1498bdfd4f8bbda8)
											 
										 
										
											2024-12-10 21:47:49 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											ao2_ref ( obj ,  - 1 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											obj  =  NULL ; 
							 
						 
					
						
							
								
									
										
										
										
											2016-06-02 14:04:45 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										}  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											/* We successfully grabbed a connection from the pool and all is well!
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											 */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											obj - > parent  =  ao2_bump ( class ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ast_debug ( 2 ,  " Reusing ODBC handle %p from class '%s' \n " ,  obj ,  name ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2010-07-23 16:19:21 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2008-01-21 18:15:57 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2016-06-02 14:04:45 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									ao2_ref ( class ,  - 1 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											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 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											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 )  { 
							 
						 
					
						
							
								
									
										
										
										
											2022-02-13 12:06:37 -07:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										char  secs [ AST_TIME_T_LEN ] ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_time_t_to_string ( negative_cache_expiration  -  time ( NULL ) ,  secs ,  sizeof ( secs ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ast_log ( LOG_WARNING ,  " Not connecting to %s. Negative connection cache for %s seconds \n " ,  obj - > parent - > name ,  secs ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2015-04-21 18:52:22 +02:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										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 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											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 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
									
										
										
										
											2018-08-15 12:31:00 -04:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									ao2_cleanup ( class_container ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ast_cli_unregister_multiple ( cli_odbc ,  ARRAY_LEN ( cli_odbc ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  0 ; 
							 
						 
					
						
							
								
									
										
										
										
											2006-04-18 18:16:32 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2006-08-21 02:11:39 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								static  int  load_module ( void )  
						 
					
						
							
								
									
										
										
										
											2004-07-08 19:58:26 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
									
										
										
										
											2018-11-19 15:10:02 -05:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									class_container  =  ao2_container_alloc_list ( AO2_ALLOC_OPT_LOCK_MUTEX ,  0 ,  NULL ,  ao2_match_by_addr ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( ! class_container )  { 
							 
						 
					
						
							
								
									
										
										
										
											2008-05-05 23:38:15 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										return  AST_MODULE_LOAD_DECLINE ; 
							 
						 
					
						
							
								
									
										
										
										
											2018-08-15 12:31:00 -04:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ( load_odbc_config ( )  = =  - 1 )  { 
							 
						 
					
						
							
								
									
										
										
										
											2006-08-31 21:00:20 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										return  AST_MODULE_LOAD_DECLINE ; 
							 
						 
					
						
							
								
									
										
										
										
											2018-08-15 12:31:00 -04:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ast_module_shutdown_ref ( ast_module_info - > self ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2008-12-05 10:31:25 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									ast_cli_register_multiple ( cli_odbc ,  ARRAY_LEN ( cli_odbc ) ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2018-08-15 12:31:00 -04:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2018-01-05 14:44:55 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									return  AST_MODULE_LOAD_SUCCESS ; 
							 
						 
					
						
							
								
									
										
										
										
											2004-07-08 19:58:26 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
									
										
										
										
											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 , 
							 
						 
					
						
							
								
									
										
										
										
											2020-11-02 08:24:42 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									. requires  =  " res_odbc_transaction " , 
							 
						 
					
						
							
								
									
										
										
										
											2015-05-05 20:49:04 -04:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								) ;