1/* Copyright (C) 2006-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
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 02111-1301 USA */
15
16#include <tap.h>
17
18#include <my_global.h>
19#include <my_sys.h>
20#include <my_atomic.h>
21#include <lf.h>
22#include <m_string.h>
23#include "../trnman.h"
24
25pthread_mutex_t rt_mutex;
26pthread_attr_t attr;
27size_t stacksize= 0;
28#define STACK_SIZE (((int)stacksize-2048)*STACK_DIRECTION)
29
30int rt_num_threads;
31int litmus;
32
33/*
34 create and end (commit or rollback) transactions randomly
35*/
36#define MAX_ITER 100
37pthread_handler_t test_trnman(void *arg)
38{
39 uint x, y, i, n;
40 TRN *trn[MAX_ITER];
41 int m= (*(int *)arg);
42
43 if (my_thread_init())
44 BAIL_OUT("my_thread_init failed!");
45
46 for (x= ((int)(intptr)(&m)); m > 0; )
47 {
48 y= x= (x*3628273133LL + 1500450271LL) % 9576890767LL; /* three prime numbers */
49 m-= n= x % MAX_ITER;
50 for (i= 0; i < n; i++)
51 {
52 trn[i]= trnman_new_trn(0);
53 if (!trn[i])
54 {
55 diag("trnman_new_trn() failed");
56 litmus++;
57 }
58 }
59 for (i= 0; i < n; i++)
60 {
61 y= (y*19 + 7) % 31;
62 trnman_end_trn(trn[i], y & 1);
63 }
64 }
65 pthread_mutex_lock(&rt_mutex);
66 rt_num_threads--;
67 pthread_mutex_unlock(&rt_mutex);
68
69 my_thread_end();
70
71 return 0;
72}
73#undef MAX_ITER
74
75void run_test(const char *test, pthread_handler handler, int n, int m)
76{
77 pthread_t *threads;
78 ulonglong now= microsecond_interval_timer();
79 int i;
80
81 litmus= 0;
82
83 threads= (pthread_t *)my_malloc(sizeof(void *)*n, MYF(0));
84 if (!threads)
85 {
86 diag("Out of memory");
87 abort();
88 }
89
90 diag("Testing %s with %d threads, %d iterations... ", test, n, m);
91 rt_num_threads= n;
92 for (i= 0; i < n ; i++)
93 if (pthread_create(threads+i, &attr, handler, &m))
94 {
95 diag("Could not create thread");
96 abort();
97 }
98 for (i= 0 ; i < n ; i++)
99 pthread_join(threads[i], 0);
100 now= microsecond_interval_timer() - now;
101 ok(litmus == 0, "Tested %s in %g secs (%d)", test, ((double)now)/1e6, litmus);
102 my_free(threads);
103}
104
105#define ok_read_from(T1, T2, RES) \
106 i= trnman_can_read_from(trn[T1], trid[T2]); \
107 ok(i == RES, "trn" #T1 " %s read from trn" #T2, i ? "can" : "cannot")
108#define start_transaction(T) \
109 trn[T]= trnman_new_trn(0); \
110 trid[T]= trn[T]->trid
111#define commit(T) trnman_commit_trn(trn[T])
112#define abort(T) trnman_abort_trn(trn[T])
113
114#define Ntrns 4
115void test_trnman_read_from()
116{
117 TRN *trn[Ntrns];
118 TrID trid[Ntrns];
119 int i;
120
121 start_transaction(0); /* start trn1 */
122 start_transaction(1); /* start trn2 */
123 ok_read_from(1, 0, 0);
124 commit(0); /* commit trn1 */
125 start_transaction(2); /* start trn4 */
126 abort(2); /* abort trn4 */
127 start_transaction(3); /* start trn5 */
128 ok_read_from(3, 0, 1);
129 ok_read_from(3, 1, 0);
130 ok_read_from(3, 2, 0);
131 ok_read_from(3, 3, 1);
132 commit(1); /* commit trn2 */
133 ok_read_from(3, 1, 0);
134 commit(3); /* commit trn5 */
135
136}
137
138int main(int argc __attribute__((unused)), char **argv)
139{
140 MY_INIT(argv[0]);
141
142 plan(7);
143
144 pthread_mutex_init(&rt_mutex, 0);
145 pthread_attr_init(&attr);
146#ifdef HAVE_PTHREAD_ATTR_GETSTACKSIZE
147 pthread_attr_getstacksize(&attr, &stacksize);
148 if (stacksize == 0)
149#endif
150 stacksize= PTHREAD_STACK_MIN;
151
152#define CYCLES 10000
153#define THREADS 10
154
155 trnman_init(0);
156
157 test_trnman_read_from();
158 run_test("trnman", test_trnman, THREADS, CYCLES);
159
160 diag("mallocs: %d", trnman_allocated_transactions);
161 {
162 ulonglong now= microsecond_interval_timer();
163 trnman_destroy();
164 now= microsecond_interval_timer() - now;
165 diag("trnman_destroy: %g", ((double)now)/1e6);
166 }
167
168 pthread_mutex_destroy(&rt_mutex);
169 my_end(0);
170 return exit_status();
171}
172
173#include "../ma_check_standalone.h"
174