#if 0 make -f Makefile -f - testSuperPool <<'_eof_' testSuperPool: testSuperPool.cpp libkernel.a LinearPool.hpp $(CXXCOMPILE) -o $@ $@.cpp libkernel.a -L../../common/util/.libs -lgeneral _eof_ exit $? #endif /* Copyright (c) 2003, 2005 MySQL AB Use is subject to license terms 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-1335 USA */ #include "SuperPool.hpp" #include "LinearPool.hpp" #include template struct A { Uint32 a[sz]; void fill() { Uint32 c = 0; for (Uint32 i = 0; i + 1 < sz; i++) { a[i] = random(); c = (c << 1) ^ a[i]; } a[sz - 1] = c; } void check() { Uint32 c = 0; for (Uint32 i = 0; i + 1 < sz; i++) { c = (c << 1) ^ a[i]; } assert(a[sz - 1] == c); } }; static Uint32 urandom(Uint32 n) { return (Uint32)random() % n; } static Uint32 random_coprime(Uint32 n) { Uint32 prime[] = { 101, 211, 307, 401, 503, 601, 701, 809, 907 }; Uint32 count = sizeof(prime) / sizeof(prime[0]); assert(n != 0); while (1) { Uint32 i = urandom(count); if (n % prime[i] != 0) return prime[i]; } } static int cmpPtrI(const void* a, const void* b) { Ptr u = *(Ptr*)a; Ptr v = *(Ptr*)b; return u.i < v.i ? -1 : u.i > v.i ? +1 : 0; } static int cmpPtrP(const void* a, const void* b) { Ptr u = *(Ptr*)a; Ptr v = *(Ptr*)b; return u.p < v.p ? -1 : u.p > v.p ? +1 : 0; } static Uint32 loopcount = 3; template static void sp_test(GroupPool& gp) { SuperPool& sp = gp.m_superPool; RecordPool rp(gp); assert(gp.m_totPages == gp.m_freeList.m_pageCount); SuperPool::RecInfo& ri = rp.m_recInfo; Uint32 pageCount = sp.m_totPages; Uint32 perPage = rp.m_recInfo.m_maxPerPage; Uint32 perPool = perPage * pageCount; ndbout << "pages=" << pageCount << " perpage=" << perPage << " perpool=" << perPool << endl; Ptr* ptrList = new Ptr [perPool]; memset(ptrList, 0x1f, perPool * sizeof(Ptr)); Uint32 verify = 1000; Uint32 useCount; Uint32 loop; for (loop = 0; loop < loopcount; loop++) { ndbout << "loop " << loop << endl; Uint32 i, j; // seize all ndbout << "seize all" << endl; for (i = 0; i < perPool + 1; i++) { if (verify == 0 || urandom(perPool) < verify) sp.verify(ri); j = i; Ptr ptr1 = { 0, RNIL }; if (! rp.seize(ptr1)) break; ptr1.p->fill(); ptr1.p->check(); Ptr ptr2 = { 0, ptr1.i }; rp.getPtr(ptr2); assert(ptr1.i == ptr2.i && ptr1.p == ptr2.p); ptrList[j] = ptr1; } sp.verify(ri); ndbout << "seized " << i << endl; assert(i == perPool); useCount = sp.getRecUseCount(ri); assert(useCount == perPool); // check duplicates ndbout << "check dups" << endl; { Ptr* ptrList2 = new Ptr [perPool]; memcpy(ptrList2, ptrList, perPool * sizeof(Ptr)); qsort(ptrList2, perPool, sizeof(Ptr), cmpPtrI); for (i = 1; i < perPool; i++) assert(ptrList2[i - 1].i != ptrList2[i].i); qsort(ptrList2, perPool, sizeof(Ptr), cmpPtrP); for (i = 1; i < perPool; i++) assert(ptrList2[i - 1].p != ptrList2[i].p); delete [] ptrList2; } // release all in various orders ndbout << "release all" << endl; Uint32 coprime = random_coprime(perPool); for (i = 0; i < perPool; i++) { if (verify == 0 || urandom(perPool) < verify) sp.verify(ri); switch (loop % 3) { case 0: // ascending j = i; break; case 1: // descending j = perPool - 1 - i; break; case 2: // pseudo-random j = (coprime * i) % perPool; break; } Ptr& ptr = ptrList[j]; assert(ptr.i != RNIL && ptr.p != 0); ptr.p->check(); rp.release(ptr); assert(ptr.i == RNIL && ptr.p == 0); } sp.verify(ri); useCount = sp.getRecUseCount(ri); assert(useCount == 0); // seize/release at random ndbout << "seize/release at random" << endl; for (i = 0; i < loopcount * perPool; i++) { if (verify == 0 || urandom(perPool) < verify) sp.verify(ri); j = urandom(perPool); Ptr& ptr = ptrList[j]; if (ptr.i == RNIL) { if (rp.seize(ptr)) ptr.p->fill(); } else { ptr.p->check(); rp.release(ptr); } } ndbout << "used " << ri.m_useCount << endl; sp.verify(ri); // release all ndbout << "release all" << endl; for (i = 0; i < perPool; i++) { if (verify == 0 || urandom(perPool) < verify) sp.verify(ri); j = i; Ptr& ptr = ptrList[j]; if (ptr.i != RNIL) { ptr.p->check(); rp.release(ptr); } } sp.verify(ri); useCount = sp.getRecUseCount(ri); assert(useCount == 0); } // done delete [] ptrList; } template static void lp_test(GroupPool& gp) { SuperPool& sp = gp.m_superPool; LinearPool lp(gp); ndbout << "linear pool test" << endl; Ptr ptr; Uint32 loop; for (loop = 0; loop < loopcount; loop++) { int count = 0; while (1) { bool ret = lp.seize(ptr); lp.verify(); if (! ret) break; assert(ptr.i == count); Ptr ptr2; ptr2.i = ptr.i; ptr2.p = 0; lp.getPtr(ptr2); assert(ptr.p == ptr2.p); count++; } assert(count != 0); ndbout << "seized " << count << endl; switch (loop % 3) { case 0: { int n = 0; while (n < count) { ptr.i = n; lp.release(ptr); lp.verify(); n++; } ndbout << "released in order" << endl; } break; case 1: { int n = count; while (n > 0) { n--; ptr.i = n; lp.release(ptr); lp.verify(); } ndbout << "released in reverse" << endl; } break; default: { int coprime = random_coprime(count); int n = 0; while (n < count) { int m = (coprime * n) % count; ptr.i = m; lp.release(ptr); lp.verify(); n++; } ndbout << "released at random" << endl; } break; } { Uint32 cnt = lp.count(); assert(cnt == 0); } // seize_index test char *used = new char [10 * count]; memset(used, false, sizeof(used)); Uint32 i, ns = 0, nr = 0; for (i = 0; i < count; i++) { Uint32 index = urandom(10 * count); if (used[index]) { ptr.i = index; lp.release(ptr); lp.verify(); nr++; } else { int i = lp.seize_index(ptr, index); assert(i >= 0); lp.verify(); if (i == 0) // no space continue; assert(ptr.i == index); Ptr ptr2; ptr2.i = ptr.i; ptr2.p = 0; lp.getPtr(ptr2); assert(ptr.p == ptr2.p); ns++; } used[index] = ! used[index]; } ndbout << "random sparse seize " << ns << " release " << nr << endl; nr = 0; for (i = 0; i < 10 * count; i++) { if (used[i]) { ptr.i = i; lp.release(ptr); lp.verify(); used[i] = false; nr++; } } ndbout << "released " << nr << endl; { Uint32 cnt = lp.count(); assert(cnt == 0); } } } static Uint32 pageSize = 32768; static Uint32 pageBits = 17; const Uint32 sz1 = 3; const Uint32 sz2 = 4; const Uint32 sz3 = 53; const Uint32 sz4 = 424; const Uint32 sz5 = 5353; typedef A T1; typedef A T2; typedef A T3; typedef A T4; typedef A T5; template static void sp_test(GroupPool& sp); template static void sp_test(GroupPool& sp); template static void sp_test(GroupPool& sp); template static void sp_test(GroupPool& sp); template static void sp_test(GroupPool& sp); // template static void lp_test(GroupPool& sp); int main(int argc, char** argv) { if (argc > 1 && strncmp(argv[1], "-l", 2) == 0) loopcount = atoi(argv[1] + 2); HeapPool sp(pageSize, pageBits); sp.setInitPages(7); sp.setMaxPages(7); if (! sp.allocMemory()) assert(false); GroupPool gp(sp); Uint16 s = (Uint16)getpid(); srandom(s); ndbout << "rand " << s << endl; int count; count = 0; while (++count <= 0) { // change to 1 to find new bug sp_test(gp); sp_test(gp); sp_test(gp); sp_test(gp); sp_test(gp); } count = 0; while (++count <= 1) { lp_test(gp); } return 0; }