/* Copyright (C) 2014 InfiniDB, Inc. Copyright (C) 2016 MariaDB Corporation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /***************************************************************************** * $Id$ * ****************************************************************************/ /** @file * This file contains the longer SessionManager stress tests. */ #include #include #include #include #include #include #include #include #include #include #include "calpontsystemcatalog.h" #include #include #include #include #include "sessionmanager.h" #include #include using namespace std; using namespace execplan; int threadStop, threadNum; static void* SMRunner(void* arg) { SessionManager* sm; int op; uint32_t seed, sessionnum; SessionManager::TxnID tmp; int tNum = reinterpret_cast(arg); struct entry { SessionManager::TxnID tid; uint32_t sessionnum; struct entry* next; }; struct entry* e; struct entry* listHead = NULL; struct entry* listTail = NULL; cerr << "Thread " << tNum << " started." << endl; seed = time(NULL) % MAXINT; sm = new SessionManager(); while (!threadStop) { sm->verifySize(); op = rand_r(&seed) % 4; // 0 = newTxnID, 1 = committed, 2 = getTxnID, 3 = delete sm; new sm sessionnum = rand_r(&seed); switch (op) { case 0: e = new struct entry; e->tid = sm->newTxnID(sessionnum, false); if (e->tid.valid == false) // SM is full { delete e; break; } e->sessionnum = sessionnum; e->next = NULL; if (listTail != NULL) listTail->next = e; else listHead = e; listTail = e; break; case 1: if (listHead == NULL) continue; sm->committed(listHead->tid); e = listHead; listHead = listHead->next; if (listHead == NULL) listTail = NULL; delete e; break; case 2: if (listHead == NULL) continue; tmp = sm->getTxnID(listHead->sessionnum); CPPUNIT_ASSERT(tmp.valid == listHead->tid.valid == true); // there's some risk of collision here if 2 threads happen to choose the // same session number // CPPUNIT_ASSERT(tmp.id == listHead->tid.id); break; case 3: delete sm; sm = new SessionManager(); break; default: cerr << "SMRunner: ??" << endl; }; } while (listHead != NULL) { e = listHead; listHead = listHead->next; delete e; } delete sm; cerr << "Thread " << tNum << " exiting." << endl; pthread_exit(0); } class ExecPlanTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(ExecPlanTest); CPPUNIT_TEST(sessionManager_3); unlink("/tmp/CalpontShm"); CPPUNIT_TEST_SUITE_END(); public: /* * destroySemaphores() and destroyShmseg() will print error messages * if there are no objects to destroy. That's OK. */ void destroySemaphores() { key_t semkey; char* semseed = "/usr/local/mariadb/columnstore/etc/Columnstore.xml"; int sems, err; // semkey = ftok(semseed, 0x2149bdd2); // these things must match in the SM constructor semkey = 0x2149bdd2; if (semkey == -1) perror("tdriver: ftok"); sems = semget(semkey, 2, 0666); if (sems != -1) { err = semctl(sems, 0, IPC_RMID); if (err == -1) perror("tdriver: semctl"); } } void destroyShmseg() { key_t shmkey; char* shmseed = "/usr/local/mariadb/columnstore/etc/Columnstore.xml"; int shms, err; // shmkey = ftok(shmseed, 0x2149bdd2); // these things much match in the SM constructor shmkey = 0x2149bdd2; if (shmkey == -1) perror("tdriver: ftok"); shms = shmget(shmkey, 0, 0666); if (shms != -1) { err = shmctl(shms, IPC_RMID, NULL); if (err == -1 && errno != EINVAL) { perror("tdriver: shmctl"); return; } } } /** This launches several threads to stress test the Session Manager */ void sessionManager_3() { const int threadCount = 4; int i; pthread_t threads[threadCount]; cerr << endl << "Multithreaded SessionManager test. " "This runs for 2 minutes." << endl; destroySemaphores(); destroyShmseg(); unlink("/tmp/CalpontShm"); threadStop = 0; for (i = 0; i < threadCount; i++) { if (pthread_create(&threads[i], NULL, SMRunner, reinterpret_cast(i + 1)) < 0) throw logic_error("Error creating threads for the Session Manager test"); usleep(1000); } sleep(120); threadStop = 1; for (i = 0; i < threadCount; i++) pthread_join(threads[i], NULL); destroySemaphores(); destroyShmseg(); } }; CPPUNIT_TEST_SUITE_REGISTRATION(ExecPlanTest); #include #include int main(int argc, char** argv) { CppUnit::TextUi::TestRunner runner; CppUnit::TestFactoryRegistry& registry = CppUnit::TestFactoryRegistry::getRegistry(); runner.addTest(registry.makeTest()); bool wasSuccessful = runner.run("", false); return (wasSuccessful ? 0 : 1); }