97 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			PHP
		
	
	
	
		
		
			
		
	
	
			97 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			PHP
		
	
	
	
|  | #
 | ||
|  | # SUMMARY
 | ||
|  | #   Check if statement reading table '$table' allows concurrent
 | ||
|  | #   inserts in it.
 | ||
|  | #
 | ||
|  | # PARAMETERS 
 | ||
|  | #   $table         Table in which concurrent inserts should be allowed.
 | ||
|  | #   $con_aux1      Name of the first auxiliary connection to be used by this
 | ||
|  | #                  script.
 | ||
|  | #   $con_aux2      Name of the second auxiliary connection to be used by this
 | ||
|  | #                  script.
 | ||
|  | #   $statement     Statement to be checked.
 | ||
|  | #   $restore_table Table which might be modified by statement to be checked
 | ||
|  | #                  and thus needs backing up before its execution and
 | ||
|  | #                  restoring after it (can be empty).
 | ||
|  | #
 | ||
|  | # EXAMPLE
 | ||
|  | #    lock_sync.test
 | ||
|  | #
 | ||
|  | --disable_result_log | ||
|  | --disable_query_log | ||
|  | 
 | ||
|  | # Reset DEBUG_SYNC facility for safety.
 | ||
|  | set debug_sync= "RESET"; | ||
|  | 
 | ||
|  | if ($restore_table) | ||
|  | { | ||
|  | --eval create temporary table t_backup select * from $restore_table; | ||
|  | } | ||
|  | 
 | ||
|  | connection $con_aux1; | ||
|  | set debug_sync='after_lock_tables_takes_lock SIGNAL parked WAIT_FOR go'; | ||
|  | --send_eval $statement; | ||
|  | 
 | ||
|  | connection $con_aux2; | ||
|  | set debug_sync='now WAIT_FOR parked'; | ||
|  | --send_eval insert into $table (i) values (0); | ||
|  | 
 | ||
|  | --enable_result_log | ||
|  | --enable_query_log | ||
|  | connection default; | ||
|  | # Wait until concurrent insert is successfully executed while
 | ||
|  | # statement being checked has its tables locked.
 | ||
|  | # We use wait_condition.inc instead of simply reaping 
 | ||
|  | # concurrent insert here in order to avoid deadlocks if test
 | ||
|  | # fails and to time out gracefully instead.
 | ||
|  | let $wait_condition= | ||
|  |   select count(*) = 0 from information_schema.processlist | ||
|  |   where info = "insert into $table (i) values (0)"; | ||
|  | --source include/wait_condition.inc | ||
|  | 
 | ||
|  | --disable_result_log | ||
|  | --disable_query_log | ||
|  | 
 | ||
|  | if ($success) | ||
|  | { | ||
|  | # Apparently concurrent insert was successfully executed.
 | ||
|  | # To be safe against wait_condition.inc succeeding due to
 | ||
|  | # races let us first reap concurrent insert to ensure that
 | ||
|  | # it has really been successfully executed.
 | ||
|  | connection $con_aux2; | ||
|  | --reap | ||
|  | connection default; | ||
|  | set debug_sync= 'now SIGNAL go'; | ||
|  | connection $con_aux1; | ||
|  | --reap | ||
|  | connection default; | ||
|  | --echo Success: '$statement' allows concurrent inserts into '$table'. | ||
|  | } | ||
|  | if (!$success) | ||
|  | { | ||
|  | # Waiting has timed out. Apparently concurrent insert was blocked.
 | ||
|  | # So to be able to continue we need to end our statement first.
 | ||
|  | set debug_sync= 'now SIGNAL go'; | ||
|  | connection $con_aux1; | ||
|  | --reap | ||
|  | connection $con_aux2; | ||
|  | --reap | ||
|  | connection default; | ||
|  | --echo Error: '$statement' doesn't allow concurrent inserts into '$table'! | ||
|  | } | ||
|  | 
 | ||
|  | --eval delete from $table where i = 0; | ||
|  | 
 | ||
|  | if ($restore_table) | ||
|  | { | ||
|  | --eval truncate table $restore_table; | ||
|  | --eval insert into $restore_table select * from t_backup; | ||
|  | drop temporary table t_backup; | ||
|  | } | ||
|  | 
 | ||
|  | # Clean-up. Reset DEBUG_SYNC facility after use.
 | ||
|  | set debug_sync= "RESET"; | ||
|  | 
 | ||
|  | --enable_result_log | ||
|  | --enable_query_log |