1 /* Copyright (C) 2014 InfiniDB, Inc.
2 Copyright (C) 2016 MariaDB Corporation
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; version 2 of
7 the License.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17 MA 02110-1301, USA. */
18
19 /*****************************************************************************
20 * $Id$
21 *
22 ****************************************************************************/
23
24 /** @file
25 * This file contains the longer SessionManager stress tests.
26 */
27
28 #include <string>
29 #include <typeinfo>
30 #include <sstream>
31 #include <stdexcept>
32 #include <iostream>
33 #include <unistd.h>
34 #include <cstdlib>
35 #include <values.h>
36 #include <errno.h>
37 #include <signal.h>
38 #include "calpontsystemcatalog.h"
39 #include <sys/types.h>
40 #include <sys/ipc.h>
41 #include <sys/sem.h>
42 #include <sys/shm.h>
43 #include "sessionmanager.h"
44 #include <cppunit/extensions/HelperMacros.h>
45 #include <boost/thread.hpp>
46
47 using namespace std;
48 using namespace execplan;
49
50 int threadStop, threadNum;
51
SMRunner(void * arg)52 static void* SMRunner(void* arg)
53 {
54 SessionManager* sm;
55 int op;
56 uint32_t seed, sessionnum;
57 SessionManager::TxnID tmp;
58 int tNum = reinterpret_cast<int>(arg);
59
60 struct entry
61 {
62 SessionManager::TxnID tid;
63 uint32_t sessionnum;
64 struct entry* next;
65 };
66
67 struct entry* e;
68 struct entry* listHead = NULL;
69 struct entry* listTail = NULL;
70
71 cerr << "Thread " << tNum << " started." << endl;
72
73 seed = time(NULL) % MAXINT;
74
75 sm = new SessionManager();
76
77 while (!threadStop)
78 {
79 sm->verifySize();
80 op = rand_r(&seed) % 4; // 0 = newTxnID, 1 = committed, 2 = getTxnID, 3 = delete sm; new sm
81 sessionnum = rand_r(&seed);
82
83 switch (op)
84 {
85 case 0:
86 e = new struct entry;
87 e->tid = sm->newTxnID(sessionnum, false);
88
89 if (e->tid.valid == false) // SM is full
90 {
91 delete e;
92 break;
93 }
94
95 e->sessionnum = sessionnum;
96 e->next = NULL;
97
98 if (listTail != NULL)
99 listTail->next = e;
100 else
101 listHead = e;
102
103 listTail = e;
104 break;
105
106 case 1:
107 if (listHead == NULL)
108 continue;
109
110 sm->committed(listHead->tid);
111 e = listHead;
112 listHead = listHead->next;
113
114 if (listHead == NULL)
115 listTail = NULL;
116
117 delete e;
118 break;
119
120 case 2:
121 if (listHead == NULL)
122 continue;
123
124 tmp = sm->getTxnID(listHead->sessionnum);
125 CPPUNIT_ASSERT(tmp.valid == listHead->tid.valid == true);
126 // there's some risk of collision here if 2 threads happen to choose the
127 // same session number
128 //CPPUNIT_ASSERT(tmp.id == listHead->tid.id);
129 break;
130
131 case 3:
132 delete sm;
133 sm = new SessionManager();
134 break;
135
136 default:
137 cerr << "SMRunner: ??" << endl;
138 };
139 }
140
141 while (listHead != NULL)
142 {
143 e = listHead;
144 listHead = listHead->next;
145 delete e;
146 }
147
148 delete sm;
149 cerr << "Thread " << tNum << " exiting." << endl;
150 pthread_exit(0);
151 }
152
153 class ExecPlanTest : public CppUnit::TestFixture
154 {
155
156 CPPUNIT_TEST_SUITE( ExecPlanTest );
157 CPPUNIT_TEST(sessionManager_3);
158 unlink("/tmp/CalpontShm");
159 CPPUNIT_TEST_SUITE_END();
160
161
162 public:
163
164 /*
165 * destroySemaphores() and destroyShmseg() will print error messages
166 * if there are no objects to destroy. That's OK.
167 */
destroySemaphores()168 void destroySemaphores()
169 {
170 key_t semkey;
171 char* semseed = "/usr/local/mariadb/columnstore/etc/Columnstore.xml";
172 int sems, err;
173
174 // semkey = ftok(semseed, 0x2149bdd2); // these things must match in the SM constructor
175 semkey = 0x2149bdd2;
176
177 if (semkey == -1)
178 perror("tdriver: ftok");
179
180 sems = semget(semkey, 2, 0666);
181
182 if (sems != -1)
183 {
184 err = semctl(sems, 0, IPC_RMID);
185
186 if (err == -1)
187 perror("tdriver: semctl");
188 }
189 }
190
destroyShmseg()191 void destroyShmseg()
192 {
193 key_t shmkey;
194 char* shmseed = "/usr/local/mariadb/columnstore/etc/Columnstore.xml";
195 int shms, err;
196
197 // shmkey = ftok(shmseed, 0x2149bdd2); // these things much match in the SM constructor
198 shmkey = 0x2149bdd2;
199
200 if (shmkey == -1)
201 perror("tdriver: ftok");
202
203 shms = shmget(shmkey, 0, 0666);
204
205 if (shms != -1)
206 {
207 err = shmctl(shms, IPC_RMID, NULL);
208
209 if (err == -1 && errno != EINVAL)
210 {
211 perror("tdriver: shmctl");
212 return;
213 }
214 }
215 }
216
217 /** This launches several threads to stress test the Session Manager
218 */
sessionManager_3()219 void sessionManager_3()
220 {
221 const int threadCount = 4;
222 int i;
223 pthread_t threads[threadCount];
224
225 cerr << endl << "Multithreaded SessionManager test. "
226 "This runs for 2 minutes." << endl;
227
228 destroySemaphores();
229 destroyShmseg();
230 unlink("/tmp/CalpontShm");
231
232 threadStop = 0;
233
234 for (i = 0; i < threadCount; i++)
235 {
236 if (pthread_create(&threads[i], NULL, SMRunner,
237 reinterpret_cast<void*>(i + 1)) < 0)
238 throw logic_error("Error creating threads for the Session Manager test");
239
240 usleep(1000);
241 }
242
243 sleep(120);
244 threadStop = 1;
245
246 for (i = 0; i < threadCount; i++)
247 pthread_join(threads[i], NULL);
248
249 destroySemaphores();
250 destroyShmseg();
251 }
252
253
254 };
255
256 CPPUNIT_TEST_SUITE_REGISTRATION( ExecPlanTest );
257
258 #include <cppunit/extensions/TestFactoryRegistry.h>
259 #include <cppunit/ui/text/TestRunner.h>
260
main(int argc,char ** argv)261 int main( int argc, char** argv)
262 {
263 CppUnit::TextUi::TestRunner runner;
264 CppUnit::TestFactoryRegistry& registry = CppUnit::TestFactoryRegistry::getRegistry();
265 runner.addTest( registry.makeTest() );
266 bool wasSuccessful = runner.run( "", false );
267 return (wasSuccessful ? 0 : 1);
268 }
269