MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
deadlock_test.c
1 /* Copyright (C) 2000-2001, 2003-2004, 2006 MySQL AB
2 
3  This program is free software; you can redistribute it and/or modify
4  it under the terms of the GNU General Public License as published by
5  the Free Software Foundation; version 2 of the License.
6 
7  This program is distributed in the hope that it will be useful,
8  but WITHOUT ANY WARRANTY; without even the implied warranty of
9  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  GNU General Public License for more details.
11 
12  You should have received a copy of the GNU General Public License
13  along with this program; if not, write to the Free Software
14  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */
15 
16 #include <mysql.h>
17 #include <stdio.h>
18 #include <stdarg.h>
19 #include <stdio.h>
20 #include <string.h>
21 #include <stdlib.h>
22 
23 typedef unsigned char uchar;
24 static void die(char* fmt, ...);
25 static void safe_query(MYSQL* mysql, char* query, int read_ok);
26 static void run_query_batch(int* order, int num_queries);
27 static void permute(int *order, int num_queries);
28 static void permute_aux(int *order, int num_queries, int* fixed);
29 static void dump_result(MYSQL* mysql, char* query);
30 
31 int count = 0;
32 
33 
34 struct query
35 {
36  MYSQL* mysql;
37  char* query;
38  int read_ok;
39  int pri;
40  int dump_result;
41 };
42 
43 MYSQL lock, sel, del_ins;
44 
45 struct query queries[] =
46 {
47  {&del_ins, "insert delayed into foo values(1)", 1, 0, 0},
48  {&del_ins, "insert delayed into foo values(1)", 1, 0, 0},
49  {&lock, "lock tables foo write", 1, 1, 0},
50  {&lock, "unlock tables", 1,2, 0},
51  {&sel, "select * from foo", 0,0, 0},
52  {&del_ins, "insert into foo values(4)", 0,3, 0},
53  {0,0,0}
54 };
55 
56 static void die(char* fmt, ...)
57 {
58  va_list args;
59  va_start(args, fmt);
60  fprintf(stderr, "ERROR: ");
61  vfprintf(stderr, fmt, args);
62  fprintf(stderr, "\n");
63  va_end(args);
64  exit(1);
65 }
66 
67 static void permute(int *order, int num_queries)
68 {
69  int *fixed;
70  if(num_queries < 2) return;
71  if(!(fixed = (int*)malloc(num_queries * sizeof(int))))
72  die("malloc() failed");
73 
74  memset(fixed, 0, num_queries * sizeof(int));
75  permute_aux(order, num_queries, fixed);
76 
77  free(fixed);
78 }
79 
80 static order_ok(int *order, int num_queries)
81 {
82  int i,j, pri_i, pri_j;
83  for(i = 0; i < num_queries; i++)
84  {
85  if((pri_i = queries[order[i]].pri))
86  for(j = i + 1; j < num_queries; j++)
87  {
88  pri_j = queries[order[j]].pri;
89  if(pri_j && pri_i > pri_j)
90  return 0;
91  }
92  }
93 
94  return 1;
95 }
96 
97 static void permute_aux(int *order, int num_queries, int* fixed)
98 {
99  int *p,*p1,j,i,tmp, num_free = 0;
100  p = fixed;
101  for(i = 0; i < num_queries; i++, p++)
102  {
103  if(!*p)
104  {
105  num_free++;
106  *p = 1;
107  for(j = 0, p1 = fixed ;
108  j < num_queries; j++,p1++)
109  {
110  if(!*p1)
111  {
112  tmp = order[i];
113  order[i] = order[j];
114  order[j] = tmp;
115  *p1 = 1;
116  permute_aux(order, num_queries, fixed);
117  tmp = order[i];
118  order[i] = order[j];
119  order[j] = tmp;
120  *p1 = 0;
121  }
122  }
123  *p = 0;
124  }
125  }
126 
127  /*printf("num_free = %d\n", num_free); */
128 
129  if(num_free <= 1)
130  {
131  count++;
132  if(order_ok(order, num_queries))
133  run_query_batch(order, num_queries);
134  }
135 }
136 
137 static void run_query_batch(int* order, int num_queries)
138 {
139  int i;
140  struct query* q;
141  int *save_order;
142  safe_query(&lock, "delete from foo", 1);
143  save_order = order;
144  for(i = 0; i < num_queries; i++,order++)
145  {
146  q = queries + *order;
147  printf("query='%s'\n", q->query);
148  safe_query(q->mysql, q->query, q->read_ok);
149  }
150  order = save_order;
151  for(i = 0; i < num_queries; i++,order++)
152  {
153  q = queries + *order;
154  if(q->dump_result)
155  dump_result(q->mysql, q->query);
156  }
157  printf("\n");
158 
159 }
160 
161 static void safe_net_read(NET* net, char* query)
162 {
163  int len;
164  len = my_net_read(net);
165  if(len == packet_error || !len)
166  die("Error running query '%s'", query);
167  if(net->read_pos[0] == 255)
168  die("Error running query '%s'", query);
169 }
170 
171 
172 static void safe_query(MYSQL* mysql, char* query, int read_ok)
173 {
174  int len;
175  NET* net = &mysql->net;
176  net_clear(net);
177  if(net_write_command(net,(uchar)COM_QUERY, query,strlen(query)))
178  die("Error running query '%s': %s", query, mysql_error(mysql));
179  if(read_ok)
180  {
181  safe_net_read(net, query);
182  }
183 }
184 
185 static void dump_result(MYSQL* mysql, char* query)
186 {
187  MYSQL_RES* res;
188  safe_net_read(&mysql->net, query);
189  res = mysql_store_result(mysql);
190  if(res)
191  mysql_free_result(res);
192 }
193 
194 static int* init_order(int* num_queries)
195 {
196  struct query* q;
197  int *order, *order_end, *p;
198  int n,i;
199 
200  for(q = queries; q->mysql; q++)
201  ;
202 
203  n = q - queries;
204  if(!(order = (int*) malloc(n * sizeof(int))))
205  die("malloc() failed");
206  order_end = order + n;
207  for(p = order,i = 0; p < order_end; p++,i++)
208  *p = i;
209  *num_queries = n;
210  return order;
211 }
212 
213 int main()
214 {
215  char* user = "root", *pass = "", *host = "localhost", *db = "test";
216  int *order, num_queries;
217  order = init_order(&num_queries);
218  if(!mysql_init(&lock) || !mysql_init(&sel) || !mysql_init(&del_ins))
219  die("error in mysql_init()");
220 
221  mysql_options(&lock, MYSQL_READ_DEFAULT_GROUP, "mysql");
222  mysql_options(&sel, MYSQL_READ_DEFAULT_GROUP, "mysql");
223  mysql_options(&del_ins, MYSQL_READ_DEFAULT_GROUP, "mysql");
224 
225  if(!mysql_real_connect(&lock, host, user, pass, db, 0,0,0 ) ||
226  !mysql_real_connect(&sel, host, user, pass, db, 0,0,0 ) ||
227  !mysql_real_connect(&del_ins, host, user, pass, db, 0,0,0 ))
228  die("Error in mysql_real_connect(): %s", mysql_error(&lock));
229  lock.reconnect= sel.reconnect= del_ins.reconnect= 1;
230 
231  permute(order, num_queries);
232  printf("count = %d\n", count);
233 
234  mysql_close(&lock);
235  mysql_close(&sel);
236  mysql_close(&del_ins);
237  free(order);
238 }