0001: /*
0002:
0003: Derby - Class org.apache.derbyTesting.unitTests.store.T_FileSystemData
0004:
0005: Licensed to the Apache Software Foundation (ASF) under one or more
0006: contributor license agreements. See the NOTICE file distributed with
0007: this work for additional information regarding copyright ownership.
0008: The ASF licenses this file to You under the Apache License, Version 2.0
0009: (the "License"); you may not use this file except in compliance with
0010: the License. You may obtain a copy of the License at
0011:
0012: http://www.apache.org/licenses/LICENSE-2.0
0013:
0014: Unless required by applicable law or agreed to in writing, software
0015: distributed under the License is distributed on an "AS IS" BASIS,
0016: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0017: See the License for the specific language governing permissions and
0018: limitations under the License.
0019:
0020: */
0021:
0022: package org.apache.derbyTesting.unitTests.store;
0023:
0024: import org.apache.derby.impl.store.raw.data.*;
0025:
0026: import org.apache.derbyTesting.unitTests.harness.T_MultiThreadedIterations;
0027: import org.apache.derbyTesting.unitTests.harness.T_Fail;
0028:
0029: import org.apache.derby.iapi.services.context.ContextService;
0030: import org.apache.derby.iapi.services.context.ContextManager;
0031: import org.apache.derby.iapi.services.locks.*;
0032: import org.apache.derby.iapi.services.monitor.Monitor;
0033: import org.apache.derby.iapi.services.sanity.SanityManager;
0034: import org.apache.derby.iapi.services.io.Storable;
0035: import org.apache.derby.iapi.services.property.PropertyUtil;
0036:
0037: import org.apache.derby.iapi.error.StandardException;
0038: import org.apache.derby.iapi.store.raw.*;
0039:
0040: import org.apache.derby.iapi.store.raw.xact.RawTransaction;
0041: import org.apache.derby.iapi.store.raw.data.RawContainerHandle;
0042:
0043: import org.apache.derby.iapi.store.access.conglomerate.LogicalUndo;
0044: import org.apache.derby.iapi.reference.Property;
0045:
0046: import java.io.*;
0047: import java.util.Properties;
0048:
0049: /**
0050: An Impl unittest for rawstore data that is based on the FileSystem
0051: */
0052:
0053: public class T_FileSystemData extends T_MultiThreadedIterations {
0054:
0055: private static final String testService = "fileSystemDataTest";
0056:
0057: static final String REC_001 = "McLaren";
0058: static final String REC_002 = "Ferrari";
0059: static final String REC_003 = "Benetton";
0060: static final String REC_004 = "Prost";
0061: static final String REC_005 = "Tyrell";
0062: static final String REC_006 = "Derby, Natscape, Goatscape, the popular names";
0063: static final String REC_007 = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz";
0064:
0065: static final String SP1 = "savepoint1";
0066: static final String SP2 = "savepoint2";
0067:
0068: static RawStoreFactory factory;
0069: static LockFactory lf;
0070: static long commonContainer = -1;
0071:
0072: static boolean testRollback; // initialize in start
0073: static final String TEST_ROLLBACK_OFF = "derby.RawStore.RollbackTestOff";
0074:
0075: private static ContextService contextService;
0076: private T_Util t_util;
0077:
0078: public T_FileSystemData() {
0079: super ();
0080: }
0081:
0082: /**
0083: @exception StandardException cannot startup the context service
0084: */
0085: public void boot(boolean create, Properties startParams)
0086: throws StandardException {
0087: super .boot(create, startParams);
0088: contextService = ContextService.getFactory();
0089: }
0090:
0091: /*
0092: ** Methods required by T_Generic
0093: */
0094:
0095: protected String getModuleToTestProtocolName() {
0096: return RawStoreFactory.MODULE;
0097: }
0098:
0099: /**
0100: Run the tests
0101:
0102: @exception T_Fail Unexpected behaviour from the API
0103: */
0104: protected void setupTest() throws T_Fail {
0105: String rollbackOff = PropertyUtil
0106: .getSystemProperty(TEST_ROLLBACK_OFF);
0107: testRollback = !Boolean.valueOf(rollbackOff).booleanValue();
0108:
0109: // don't automatic boot this service if it gets left around
0110: if (startParams == null) {
0111: startParams = new Properties();
0112: }
0113:
0114: // see if we are testing encryption
0115: startParams = T_Util.setEncryptionParam(startParams);
0116:
0117: startParams.put(Property.NO_AUTO_BOOT, Boolean.TRUE.toString());
0118: // remove the service directory to ensure a clean run
0119: startParams.put(Property.DELETE_ON_CREATE, Boolean.TRUE
0120: .toString());
0121:
0122: try {
0123: factory = (RawStoreFactory) Monitor
0124: .createPersistentService(
0125: getModuleToTestProtocolName(), testService,
0126: startParams);
0127: if (factory == null) {
0128: throw T_Fail.testFailMsg(getModuleToTestProtocolName()
0129: + " service not started.");
0130: }
0131:
0132: lf = factory.getLockFactory();
0133: if (lf == null) {
0134: throw T_Fail
0135: .testFailMsg("LockFactory.MODULE not found");
0136: }
0137: } catch (StandardException mse) {
0138: throw T_Fail.exceptionFail(mse);
0139: }
0140:
0141: t_util = new T_Util(factory, lf, contextService);
0142: commonContainer = commonContainer();
0143:
0144: return;
0145: }
0146:
0147: /**
0148: * T_MultiThreadedIteration method
0149: *
0150: * @exception T_Fail Unexpected behaviour from the API
0151: */
0152: protected void joinSetupTest() throws T_Fail {
0153:
0154: T_Fail
0155: .T_ASSERT(factory != null,
0156: "raw store factory not setup ");
0157: T_Fail.T_ASSERT(contextService != null,
0158: "Context service not setup ");
0159: T_Fail.T_ASSERT(commonContainer != -1,
0160: "common container not setup ");
0161:
0162: t_util = new T_Util(factory, lf, contextService);
0163:
0164: }
0165:
0166: protected T_MultiThreadedIterations newTestObject() {
0167: return new T_FileSystemData();
0168: }
0169:
0170: /**
0171: run the test
0172:
0173: @exception T_Fail Unexpected behaviour from the API
0174: */
0175: protected void runTestSet() throws T_Fail {
0176:
0177: // get a utility helper
0178:
0179: ContextManager cm1 = contextService.newContextManager();
0180: contextService.setCurrentContextManager(cm1);
0181:
0182: try {
0183:
0184: runCostEstimationTests();
0185: runAllocationTests();
0186:
0187: } catch (StandardException se) {
0188:
0189: cm1.cleanupOnError(se);
0190: throw T_Fail.exceptionFail(se);
0191: } finally {
0192:
0193: contextService.resetCurrentContextManager(cm1);
0194: }
0195: }
0196:
0197: /*
0198: * create a container that all threads can use
0199: */
0200: private long commonContainer() throws T_Fail {
0201: ContextManager cm1 = contextService.newContextManager();
0202: contextService.setCurrentContextManager(cm1);
0203: long cid;
0204:
0205: try {
0206: Transaction t = t_util.t_startTransaction();
0207: cid = t_util.t_addContainer(t, 0);
0208: t_util.t_commit(t);
0209: t.close();
0210: } catch (StandardException se) {
0211:
0212: cm1.cleanupOnError(se);
0213: throw T_Fail.exceptionFail(se);
0214: } finally {
0215: contextService.resetCurrentContextManager(cm1);
0216: }
0217: return cid;
0218: }
0219:
0220: protected void runCostEstimationTests() throws T_Fail,
0221: StandardException {
0222: CostEstimationTest1();
0223: }
0224:
0225: protected void runAllocationTests() throws T_Fail,
0226: StandardException {
0227: // don't run these for > 2 threads
0228: if (threadNumber < 2) {
0229: AllocTest1(); // test remove and reuse of page
0230: AllocTest2(); // test remove and drop and rollback of remove
0231: AllocTest3(); // test multiple alloc page
0232: AllocTest4(); // test preallocation
0233: }
0234:
0235: // can't get this test to pass consistently because it depends on
0236: // timing of the cache.
0237: // AllocTest5(); // test gettting 1/2 filled page for insert
0238:
0239: AllocMTest1(commonContainer); // test multi thread access to the same container
0240: }
0241:
0242: /**
0243: @exception T_Fail Unexpected behaviour from the API
0244: @exception StandardException Standard Derby error policy
0245: */
0246: protected void CostEstimationTest1() throws StandardException,
0247: T_Fail {
0248: // getEstimatedRowCount(0), setEstimatedRowCount(long count, int flag),
0249: // getEstimatedPageCount(int flag);
0250:
0251: Transaction t = t_util.t_startTransaction();
0252: long cid = t_util.t_addContainer(t, 0);
0253: t_util.t_commit(t);
0254:
0255: ContainerHandle c = t_util.t_openContainer(t, 0, cid, true);
0256:
0257: try {
0258: int numRows = 10;
0259: T_RawStoreRow row = new T_RawStoreRow(REC_001);
0260: RecordHandle rh[] = new RecordHandle[numRows];
0261:
0262: // insert numRows rows into container
0263: for (int i = 0; i < numRows; i++)
0264: rh[i] = t_util.t_insert(c, row);
0265:
0266: t_util.t_commit(t);
0267:
0268: c = t_util.t_openContainer(t, 0, cid, true);
0269: if ((c.getEstimatedRowCount(0) != numRows)
0270: && (c.getEstimatedRowCount(0) != (numRows - 1))) {
0271: // due to timing, sometimes estimate row count is 9 rather than
0272: // 10.
0273:
0274: throw T_Fail
0275: .testFailMsg("expect estimated row count to be "
0276: + (numRows - 1)
0277: + " or "
0278: + numRows
0279: + ", got " + c.getEstimatedRowCount(0));
0280: }
0281:
0282: // now update them that cause overflowing - expect the same row count
0283: T_RawStoreRow longRow = new T_RawStoreRow(REC_007);
0284: for (int i = 0; i < numRows; i++)
0285: t_util.t_update(c, rh[i], longRow);
0286:
0287: t_util.t_commit(t);
0288:
0289: c = t_util.t_openContainer(t, 0, cid, true);
0290: if (c.getEstimatedRowCount(0) != numRows)
0291:
0292: if ((c.getEstimatedRowCount(0) != numRows)
0293: && (c.getEstimatedRowCount(0) != (numRows - 1))) {
0294: // due to timing, sometimes estimate row count is 9 rather than
0295: // 10.
0296:
0297: throw T_Fail
0298: .testFailMsg("expect after update same estimated row count, but it is not."
0299: + "expect estimated row count to be "
0300: + (numRows - 1)
0301: + " or "
0302: + numRows
0303: + ", got "
0304: + c.getEstimatedRowCount(0));
0305: }
0306:
0307: // now focibly set the row count
0308: c.setEstimatedRowCount(2 * numRows, 0);
0309:
0310: if (c.getEstimatedRowCount(0) != 2 * numRows)
0311: throw T_Fail
0312: .testFailMsg("forcibly setting estimated row count doesn't seem to work");
0313:
0314: // now purge some rows, this should alter the row count.
0315: Page p = null;
0316: long pnum = 0;
0317: long purgedCount = 0;
0318: for (p = c.getFirstPage(); p != null; p = c
0319: .getNextPage(pnum)) {
0320: int rcount = p.recordCount() / 3;
0321: pnum = p.getPageNumber();
0322:
0323: p.deleteAtSlot(0, true, (LogicalUndo) null);
0324: p.purgeAtSlot(rcount, rcount, true); // purget the middle 1/3 of the page
0325: purgedCount += rcount + 1;
0326:
0327: p.unlatch();
0328: }
0329:
0330: t_util.t_commit(t);
0331:
0332: c = t_util.t_openContainer(t, 0, cid, true);
0333: if (c.getEstimatedRowCount(0) != (2 * numRows - purgedCount))
0334: throw T_Fail.testFailMsg("expect "
0335: + (2 * numRows - purgedCount) + " after purge");
0336:
0337: // now get rid of some pages to alter the row count
0338: REPORT("before page delete, estRC = " + (2 * numRows)
0339: + " - " + purgedCount);
0340:
0341: for (p = c.getFirstPage(); p != null; p = c
0342: .getNextPage(pnum)) {
0343: pnum = p.getPageNumber();
0344: if ((pnum % 2) == 0) {
0345: purgedCount += p.nonDeletedRecordCount();
0346: c.removePage(p);
0347: } else
0348: p.unlatch();
0349: }
0350:
0351: t_util.t_commit(t);
0352:
0353: c = t_util.t_openContainer(t, 0, cid, true);
0354: if (c.getEstimatedRowCount(0) != (2 * numRows - purgedCount))
0355: throw T_Fail.testFailMsg("expect "
0356: + (2 * numRows - purgedCount)
0357: + " after page remove, got "
0358: + c.getEstimatedRowCount(0));
0359:
0360: PASS("CostEstimationTest1");
0361: } finally {
0362: t_util.t_commit(t);
0363: t.close();
0364: }
0365:
0366: }
0367:
0368: protected void AllocTest1() throws StandardException, T_Fail {
0369: /**
0370: test remove and reuse of page
0371: */
0372: Transaction t = t_util.t_startTransaction();
0373:
0374: try {
0375: long cid = t_util.t_addContainer(t, 0);
0376: t_util.t_commit(t);
0377:
0378: ContainerHandle c = t_util.t_openContainer(t, 0, cid, true);
0379:
0380: // create 5 pages, each insert a row into it, then remove 2 of them
0381:
0382: Page page1 = t_util.t_getPage(c,
0383: ContainerHandle.FIRST_PAGE_NUMBER);
0384: long p1 = page1.getPageNumber();
0385: T_RawStoreRow row1 = new T_RawStoreRow(REC_001);
0386: t_util.t_insert(page1, row1);
0387:
0388: Page page2 = t_util.t_addPage(c);
0389: long p2 = page2.getPageNumber();
0390: T_RawStoreRow row2 = new T_RawStoreRow(REC_002);
0391: int rid2 = t_util.t_insert(page2, row2).getId();
0392:
0393: Page page3 = t_util.t_addPage(c);
0394: long p3 = page3.getPageNumber();
0395: T_RawStoreRow row3 = new T_RawStoreRow(REC_003);
0396: t_util.t_insert(page3, row3);
0397:
0398: Page page4 = t_util.t_addPage(c);
0399: long p4 = page4.getPageNumber();
0400: T_RawStoreRow row4 = new T_RawStoreRow(REC_004);
0401: int rid4 = t_util.t_insert(page4, row4).getId();
0402:
0403: Page page5 = t_util.t_addPage(c);
0404: long p5 = page5.getPageNumber();
0405: T_RawStoreRow row5 = new T_RawStoreRow(REC_005);
0406: t_util.t_insert(page5, row5);
0407:
0408: t_util.t_removePage(c, page2);
0409: t_util.t_removePage(c, page4);
0410: t_util.t_commit(t);
0411:
0412: // now all the pages are unlatched
0413: // pages 2, 4 has been removed, pages 1, 3, 5 has not
0414: // make sure pages that are removed cannot be found again
0415: c = t_util.t_openContainer(t, 0, cid, true);
0416:
0417: if (SanityManager.DEBUG)
0418: SanityManager.DEBUG("SpaceTrace", "containeropened");
0419:
0420: Page p = c.getFirstPage();
0421: if (p == null)
0422: throw T_Fail
0423: .testFailMsg("get first page failed: expect "
0424: + p1 + " got null");
0425: if (p.getPageNumber() != p1)
0426: throw T_Fail
0427: .testFailMsg("get first page failed: expect "
0428: + p1 + " got " + p.getPageNumber());
0429:
0430: t_util.t_commit(t);
0431:
0432: // closing the transaction many times to see if we can get the
0433: // deallocated page to free
0434:
0435: c = t_util.t_openContainer(t, 0, cid, true);
0436: p = c.getNextPage(p1);
0437: if (p == null || p.getPageNumber() != p3)
0438: throw T_Fail.testFailMsg("get next page failed");
0439: t_util.t_commit(t);
0440:
0441: c = t_util.t_openContainer(t, 0, cid, true);
0442: p = c.getNextPage(p3);
0443: if (p == null || p.getPageNumber() != p5)
0444: throw T_Fail.testFailMsg("get next page failed");
0445: t_util.t_commit(t);
0446:
0447: c = t_util.t_openContainer(t, 0, cid, true);
0448: p = t_util.t_getLastPage(c); // make sure it skips over p5
0449: if (p == null || p.getPageNumber() != p5)
0450: throw T_Fail.testFailMsg("getLastPage failed");
0451: t_util.t_commit(t);
0452:
0453: // see if we can get any deallocated page back in 10 attempts
0454: // of add page
0455: int tries = 100;
0456: T_RawStoreRow row6 = new T_RawStoreRow(REC_001);
0457:
0458: long pnums[] = new long[tries];
0459: int rids[] = new int[tries];
0460: pnums[0] = p2; // pages 2 and 4 have been removed for a long time
0461: rids[0] = rid2;
0462: pnums[1] = p4;
0463: rids[1] = rid4;
0464:
0465: int match = -1;
0466: int i;
0467: for (i = 2; match < 0 && i < tries; i++) {
0468: c = t_util.t_openContainer(t, 0, cid, true);
0469: p = t_util.t_addPage(c);
0470: pnums[i] = p.getPageNumber();
0471:
0472: for (int j = 0; j < i - 1; j++) {
0473: if (pnums[j] == pnums[i]) {
0474: match = j;
0475: break;
0476: }
0477: }
0478:
0479: if (match >= 0) {
0480: // p is a reused one, make sure it is empty
0481: t_util.t_checkEmptyPage(p);
0482: RecordHandle rh = t_util.t_insert(p, row6);
0483: if (rh.getId() == rids[match])
0484: throw T_Fail
0485: .testFailMsg("reused page recordId is not preserved");
0486: break;
0487: } else
0488: rids[i] = t_util.t_insert(p, row6).getId();
0489:
0490: t_util.t_removePage(c, p);
0491: t_util.t_commit(t);
0492: }
0493: t_util.t_dropContainer(t, 0, cid); // cleanup
0494:
0495: if (match >= 0)
0496: PASS("AllocTest1 success in " + i + " tries");
0497: else
0498: REPORT("AllocTest1 Not successful in "
0499: + i
0500: + " tries. This is a timing depenedent test so this is not necessarily an indication of failure.");
0501: } finally {
0502: t_util.t_commit(t);
0503: t.close();
0504: }
0505:
0506: }
0507:
0508: protected void AllocTest2() throws StandardException, T_Fail {
0509: /**
0510: More Test remove and reuse of page
0511: */
0512:
0513: Transaction t = t_util.t_startTransaction();
0514: int numpages = 30;
0515:
0516: try {
0517: long cid = t_util.t_addContainer(t, 0);
0518: ContainerHandle c = t_util.t_openContainer(t, 0, cid, true);
0519:
0520: Page[] page = new Page[numpages];
0521:
0522: for (int i = 0; i < numpages; i++) {
0523: page[i] = t_util.t_addPage(c);
0524: t_util.t_removePage(c, page[i]);
0525: }
0526:
0527: // make sure a dropped container does not cause problem for page
0528: // that's been removed
0529: t_util.t_dropContainer(t, 0, cid);
0530:
0531: t_util.t_commit(t);
0532:
0533: if (testRollback) {
0534: cid = t_util.t_addContainer(t, 0);
0535: c = t_util.t_openContainer(t, 0, cid, true);
0536:
0537: for (int i = 0; i < numpages; i++) {
0538: page[i] = t_util.t_addPage(c);
0539: t_util.t_removePage(c, page[i]);
0540: }
0541:
0542: t_util.t_abort(t);
0543: }
0544: } finally {
0545: t_util.t_commit(t);
0546: t.close();
0547: }
0548:
0549: PASS("AllocTest2");
0550: }
0551:
0552: protected void AllocTest3() throws StandardException, T_Fail {
0553: /* test multiple alloc pages */
0554:
0555: if (!SanityManager.DEBUG) {
0556: REPORT("allocTest3 cannot be run on an insane server");
0557: return;
0558: } else {
0559: SanityManager.DEBUG_SET(AllocPage.TEST_MULTIPLE_ALLOC_PAGE);
0560:
0561: Transaction t = t_util.t_startTransaction();
0562:
0563: try {
0564: long cid = t_util.t_addContainer(t, 0);
0565: t_util.t_commit(t);
0566:
0567: ContainerHandle c = t_util.t_openContainer(t, 0, cid,
0568: true);
0569:
0570: T_RawStoreRow row = new T_RawStoreRow(REC_001);
0571: int numrows = 10; // create 10 pages with 1 row each
0572:
0573: String threadName = Thread.currentThread().getName();
0574:
0575: Page page;
0576: for (int i = 0; i < numrows; i++) {
0577: page = t_util.t_addPage(c);
0578: t_util.t_insert(page, row);
0579: page.unlatch();
0580: }
0581:
0582: int checkrows = 0;
0583: long pnum;
0584: for (page = c.getFirstPage(); page != null; page = c
0585: .getNextPage(pnum)) {
0586: pnum = page.getPageNumber();
0587: if (page.recordCount() > 0) {
0588: t_util.t_checkFetchFirst(page, REC_001);
0589: checkrows++;
0590: }
0591: page.unlatch();
0592: }
0593: if (checkrows != numrows)
0594: throw T_Fail.testFailMsg("number of rows differ");
0595:
0596: t.setSavePoint(SP1, null);
0597:
0598: // now remove 1/2 of the pages and check results
0599: int removedPages = 0;
0600: for (page = c.getFirstPage(); page != null; page = c
0601: .getNextPage(pnum)) {
0602: pnum = page.getPageNumber();
0603: if ((pnum % 2) == 0) {
0604: t_util.t_removePage(c, page);
0605: removedPages++;
0606: } else
0607: page.unlatch();
0608: }
0609:
0610: checkrows = 0;
0611: for (page = c.getFirstPage(); page != null; page = c
0612: .getNextPage(pnum)) {
0613: pnum = page.getPageNumber();
0614: if (page.recordCount() > 0) {
0615: t_util.t_checkFetchFirst(page, REC_001);
0616: checkrows++;
0617: }
0618: page.unlatch();
0619: }
0620: if (checkrows != numrows - removedPages)
0621: throw T_Fail.testFailMsg("number of rows differ");
0622:
0623: // remove every page backwards
0624: long lastpage = ContainerHandle.INVALID_PAGE_NUMBER;
0625: while ((page = t_util.t_getLastPage(c)) != null) // remove the last page
0626: {
0627: if (lastpage == page.getPageNumber())
0628: throw T_Fail
0629: .testFailMsg("got a removed last page");
0630:
0631: lastpage = page.getPageNumber();
0632: t_util.t_removePage(c, page);
0633: }
0634:
0635: if (c.getFirstPage() != null)
0636: throw T_Fail
0637: .testFailMsg("get last page returns null but get fisrt page retuns a page");
0638:
0639: t.rollbackToSavePoint(SP1, null); // roll back removes
0640: c = t_util.t_openContainer(t, 0, cid, true);
0641:
0642: checkrows = 0;
0643: for (page = c.getFirstPage(); page != null; page = c
0644: .getNextPage(pnum)) {
0645: pnum = page.getPageNumber();
0646: if (page.recordCount() > 0) {
0647: t_util.t_checkFetchFirst(page, REC_001);
0648: checkrows++;
0649: }
0650: page.unlatch();
0651: }
0652: if (checkrows != numrows)
0653: throw T_Fail.testFailMsg(threadName
0654: + "number of rows differ expect " + numrows
0655: + " got " + checkrows);
0656:
0657: t_util.t_abort(t); // abort the whole thing, no rows left
0658: c = t_util.t_openContainer(t, 0, cid, true);
0659:
0660: int countPages = 0;
0661: for (page = c.getFirstPage(); page != null; page = c
0662: .getNextPage(pnum)) {
0663: countPages++;
0664: pnum = page.getPageNumber();
0665: if (page.nonDeletedRecordCount() > 0) {
0666: throw T_Fail
0667: .testFailMsg("failed to remove everything "
0668: + page.nonDeletedRecordCount()
0669: + " rows left on page " + pnum);
0670: }
0671: page.unlatch();
0672: }
0673:
0674: if (countPages < numrows)
0675: throw T_Fail
0676: .testFailMsg("rollback of user transaction should not remove allocated pages");
0677:
0678: t_util.t_dropContainer(t, 0, cid);
0679:
0680: } finally {
0681: SanityManager
0682: .DEBUG_CLEAR(AllocPage.TEST_MULTIPLE_ALLOC_PAGE);
0683: t_util.t_commit(t);
0684: t.close();
0685: }
0686: PASS("AllocTest3");
0687: }
0688: }
0689:
0690: protected void AllocTest4() throws StandardException, T_Fail {
0691: if (!SanityManager.DEBUG) {
0692: REPORT("allocTest3 cannot be run on an insane server");
0693: return;
0694: } else {
0695:
0696: SanityManager.DEBUG_SET(AllocPage.TEST_MULTIPLE_ALLOC_PAGE);
0697: Transaction t = t_util.t_startTransaction();
0698:
0699: try {
0700: ////////////////////////////////////////////////////////
0701: // first test preallocation large table
0702: ////////////////////////////////////////////////////////
0703: Properties tableProperties = new Properties();
0704: tableProperties.put(Property.PAGE_SIZE_PARAMETER,
0705: Integer.toString(1024));
0706: tableProperties.put(
0707: RawStoreFactory.CONTAINER_INITIAL_PAGES,
0708: Integer.toString(100));
0709:
0710: long cid1 = t.addContainer(0,
0711: ContainerHandle.DEFAULT_ASSIGN_ID,
0712: ContainerHandle.MODE_DEFAULT, tableProperties,
0713: 0);
0714:
0715: if (cid1 < 0)
0716: throw T_Fail.testFailMsg("addContainer");
0717:
0718: ContainerHandle c1 = t_util.t_openContainer(t, 0, cid1,
0719: true);
0720:
0721: Page p1 = c1.getFirstPage();
0722: if (p1.getPageNumber() != ContainerHandle.FIRST_PAGE_NUMBER)
0723: throw T_Fail
0724: .testFailMsg("expect first page to have FIRST_PAGE_NUMBER");
0725: p1.unlatch();
0726:
0727: if (c1.getNextPage(ContainerHandle.FIRST_PAGE_NUMBER) != null)
0728: throw T_Fail
0729: .testFailMsg("expect to have only 1 page allocated");
0730:
0731: t_util.t_commit(t);
0732:
0733: REPORT("AllocTest4 - create preallocated container "
0734: + cid1);
0735:
0736: ////////////////////////////////////////////////////////
0737: // next test special addpage interface
0738: ////////////////////////////////////////////////////////
0739: long cid2 = t_util.t_addContainer(t, 0, 1024, 0, 1,
0740: false);
0741: t_util.t_commit(t);
0742:
0743: ContainerHandle c2 = t_util.t_openContainer(t, 0, cid2,
0744: true);
0745:
0746: // add page for bulk load
0747: p1 = c2.addPage(ContainerHandle.ADD_PAGE_BULK);
0748: long pnum1 = p1.getPageNumber();
0749: p1.unlatch();
0750:
0751: // since the interface does not guarentee that anything special will
0752: // actually happen, can't really test that. Just make sure that
0753: // everything else works
0754: Page p2 = c2.addPage();
0755: long pnum2 = p2.getPageNumber();
0756: p2.unlatch();
0757:
0758: Page p3 = c2.addPage(ContainerHandle.ADD_PAGE_BULK);
0759: long pnum3 = p3.getPageNumber();
0760: p3.unlatch();
0761:
0762: Page p = c2.getFirstPage(); // this is the first page that came with the
0763: // container when it was created
0764:
0765: try {
0766: long pnum0 = p.getPageNumber();
0767: p.unlatch();
0768: p = c2.getNextPage(pnum0);
0769: if (p.getPageNumber() != pnum1)
0770: throw T_Fail.testFailMsg("expected pagenum "
0771: + pnum1 + " got " + p.getPageNumber());
0772: p.unlatch();
0773: p = null;
0774:
0775: p = c2.getNextPage(pnum1);
0776: if (p.getPageNumber() != pnum2)
0777: throw T_Fail.testFailMsg("expected pagenum "
0778: + pnum2 + " got " + p.getPageNumber());
0779: p.unlatch();
0780: p = null;
0781:
0782: p = c2.getNextPage(pnum2);
0783: if (p.getPageNumber() != pnum3)
0784: throw T_Fail.testFailMsg("expected pagenum "
0785: + pnum3 + " got " + p.getPageNumber());
0786: p.unlatch();
0787: p = null;
0788:
0789: p = c2.getNextPage(pnum3);
0790: if (p != null)
0791: throw T_Fail
0792: .testFailMsg("expected null page after "
0793: + pnum3
0794: + " got "
0795: + p.getPageNumber());
0796:
0797: // make sure rollback is unaffected
0798: if (testRollback) {
0799: t_util.t_abort(t);
0800: c2 = t_util.t_openContainer(t, 0, cid2, true);
0801: p = t_util.t_getPage(c2, pnum0);
0802: t_util.t_checkEmptyPage(p);
0803: p.unlatch();
0804: p = null;
0805:
0806: p = t_util.t_getPage(c2, pnum1);
0807: t_util.t_checkEmptyPage(p);
0808: p.unlatch();
0809: p = null;
0810:
0811: p = t_util.t_getPage(c2, pnum2);
0812: t_util.t_checkEmptyPage(p);
0813: p.unlatch();
0814: p = null;
0815:
0816: p = t_util.t_getPage(c2, pnum3);
0817: t_util.t_checkEmptyPage(p);
0818: p.unlatch();
0819: p = null;
0820:
0821: p = t_util.t_getLastPage(c2);
0822: if (p.getPageNumber() != pnum3)
0823: throw T_Fail
0824: .testFailMsg("expect last page to be "
0825: + pnum3
0826: + " got "
0827: + p.getPageNumber());
0828: p.unlatch();
0829: p = null;
0830: }
0831: } finally {
0832: if (p != null)
0833: p.unlatch();
0834: p = null;
0835: }
0836: REPORT("AllocTest4 - special addPage interface " + cid2);
0837:
0838: ////////////////////////////////////////////////////////
0839: // next test preallocate interface
0840: ////////////////////////////////////////////////////////
0841: long cid3 = t_util.t_addContainer(t, 0, 1024);
0842: ContainerHandle c3 = t_util.t_openContainer(t, 0, cid3,
0843: true);
0844:
0845: // now preallocate 10 pages
0846: c3.preAllocate(10);
0847:
0848: p1 = c3.getFirstPage();
0849: if (p1.getPageNumber() != ContainerHandle.FIRST_PAGE_NUMBER)
0850: throw T_Fail
0851: .testFailMsg("expect first page to have FIRST_PAGE_NUMBER");
0852: p1.unlatch();
0853:
0854: if (c3.getNextPage(ContainerHandle.FIRST_PAGE_NUMBER) != null)
0855: throw T_Fail
0856: .testFailMsg("expect to have only 1 page allocated");
0857:
0858: REPORT("AllocTest4 - preallocate interface " + cid3);
0859:
0860: PASS("AllocTest4 ");
0861:
0862: } finally {
0863: SanityManager
0864: .DEBUG_CLEAR(AllocPage.TEST_MULTIPLE_ALLOC_PAGE);
0865: t_util.t_commit(t);
0866: t.close();
0867: }
0868: }
0869: }
0870:
0871: protected void AllocTest5() throws StandardException, T_Fail {
0872: // first create 10 1/2 filled pages with various degree of fillness
0873: Transaction t = t_util.t_startTransaction();
0874:
0875: try {
0876: long cid = t_util.t_addContainer(t, 0, 1024, 0, 90, false);
0877: ContainerHandle c = t_util.t_openContainer(t, 0, cid, true);
0878: Page p;
0879:
0880: // the number of rows that is expected to fit into one page
0881: // secret raw store calculation for 1 column rows
0882: int numRows = (1024 - 60) / (95 + 8);
0883:
0884: T_RawStoreRow rows[] = new T_RawStoreRow[numRows];
0885:
0886: for (int j = 0; j < numRows; j++)
0887: rows[j] = new T_RawStoreRow("row " + j);
0888:
0889: for (int i = 0; i < numRows; i++) {
0890: p = t_util.t_addPage(c);
0891:
0892: // validate allocation cache by getting the first page
0893: t_util.t_getPage(c, 1).unlatch();
0894:
0895: // insert different number of rows into these pages
0896: for (int j = 0; j <= i; j++) {
0897: if (t_util.t_insert(p, rows[j]) == null)
0898: throw T_Fail.testFailMsg("failed to insert "
0899: + (j + 1) + " rows into page " + p);
0900: }
0901:
0902: p.unlatch();
0903: }
0904:
0905: // page 1 has 0 row
0906: // page 2 has 1 row
0907: // page 3 has 2 rows
0908: // page 4 has 3 rows
0909: // page 5 has 4 rows
0910: // page 6 has 5 rows (filled)
0911: // page 7 has 6 rows (filled)
0912: // page 8 has 7 rows (filled)
0913: // page 9 has 8 rows (filled)
0914: // page 10 has 9 rows (filled)
0915:
0916: // these pages should be accounted for correctly because each
0917: // subsequent page has > 1/8 for all the records in the container
0918:
0919: // now go thru and use up all the space
0920: p = c.getPageForInsert(0);
0921: if (p != null)
0922: throw T_Fail.testFailMsg("Expect last page to be full");
0923:
0924: // now go thru and use up all the space - since we skipped page 1
0925: // on the first loop, it won't know it is a 1/2 filled page.
0926: for (int i = 2; i < 6; i++) {
0927: p = c
0928: .getPageForInsert(ContainerHandle.GET_PAGE_UNFILLED);
0929: if (p == null)
0930: throw T_Fail
0931: .testFailMsg("Expect next unfilled page to be "
0932: + i);
0933:
0934: if (p.getPageNumber() != i)
0935: throw T_Fail
0936: .testFailMsg("Expect next unfilled page to be "
0937: + i
0938: + ", it is "
0939: + p.getPageNumber());
0940:
0941: t_util.t_insert(p, rows[i]);
0942: p.unlatch();
0943:
0944: // we should keep getting the same page back until it is full
0945: while ((p = c.getPageForInsert(0)) != null) {
0946: if (p.getPageNumber() != i)
0947: throw T_Fail
0948: .testFailMsg("Don't expect page number to change from "
0949: + i
0950: + " to "
0951: + p.getPageNumber());
0952: t_util.t_insert(p, rows[i]);
0953: p.unlatch();
0954: }
0955:
0956: }
0957:
0958: p = c.getPageForInsert(ContainerHandle.GET_PAGE_UNFILLED);
0959: if (p != null)
0960: throw T_Fail
0961: .testFailMsg("don't expect any more pages to be found");
0962:
0963: } finally {
0964: t_util.t_commit(t);
0965: t.close();
0966: }
0967: PASS("AllocTest5 ");
0968:
0969: }
0970:
0971: /*
0972: * MT tests on the same container
0973: */
0974: protected void AllocMTest1(long cid) throws StandardException,
0975: T_Fail {
0976: if (SanityManager.DEBUG) {
0977: SanityManager.DEBUG_SET(AllocPage.TEST_MULTIPLE_ALLOC_PAGE);
0978:
0979: // each thread will add N pages and remove N pages and still finds
0980: // its own pages. Do that serveral times.
0981: int N = 20;
0982:
0983: RecordHandle rh[] = new RecordHandle[N];
0984:
0985: Transaction t = t_util.t_startTransaction();
0986:
0987: try {
0988: T_RawStoreRow row = new T_RawStoreRow(REC_002);
0989: ContainerHandle c;
0990: Page p;
0991:
0992: for (int iteration = 0; iteration < 5; iteration++) {
0993: for (int i = 0; i < N; i++) {
0994: c = t_util.t_openContainer(t, 0, cid, true);
0995:
0996: p = t_util.t_addPage(c);
0997: rh[i] = t_util.t_insert(p, row);
0998: p.unlatch();
0999:
1000: t_util.t_commit(t);
1001: }
1002:
1003: for (int i = 0; i < N; i++) {
1004: c = t_util.t_openContainer(t, 0, cid, true);
1005: t_util.t_checkFetch(c, rh[i], REC_002);
1006:
1007: t.setSavePoint(SP1, null);
1008:
1009: p = t_util.t_getPage(c, rh[i].getPageNumber());
1010: t_util.t_removePage(c, p);
1011:
1012: if ((iteration % 3) == 1) {
1013: t.rollbackToSavePoint(SP1, null);
1014: }
1015:
1016: // sometimes commit sometimes abort
1017: if (iteration % 2 == 0)
1018: t_util.t_abort(t);
1019: else
1020: t_util.t_commit(t);
1021: }
1022:
1023: // if I aborted, remove them now
1024: if ((iteration % 2) == 0 || (iteration % 3) == 1) {
1025: for (int i = 0; i < N; i++) {
1026: c = t_util.t_openContainer(t, 0, cid, true);
1027: t_util.t_checkFetch(c, rh[i], REC_002);
1028:
1029: p = t_util.t_getPage(c, rh[i]
1030: .getPageNumber());
1031: t_util.t_removePage(c, p);
1032: t_util.t_commit(t);
1033: }
1034: }
1035:
1036: // at any given time, there should be <= (N*numthread)+1 pages
1037: int max = (N * getNumThreads()) + 1;
1038:
1039: c = t_util.t_openContainer(t, 0, cid, false);
1040: long pnum = 0;
1041: int countPages = 0;
1042:
1043: for (p = c.getFirstPage(); p != null; p = c
1044: .getNextPage(pnum)) {
1045: countPages++;
1046: pnum = p.getPageNumber();
1047: p.unlatch();
1048: t_util.t_commit(t); // release container lock
1049:
1050: c = t_util.t_openContainer(t, 0, cid, false);
1051: }
1052:
1053: t_util.t_commit(t); // release container lock
1054:
1055: if (countPages > max)
1056: throw T_Fail
1057: .testFailMsg("some pages may not be reused, expect "
1058: + max + " got " + countPages);
1059: else
1060: REPORT("AllocMTest1 got " + countPages);
1061: }
1062:
1063: } finally {
1064: SanityManager
1065: .DEBUG_CLEAR(AllocPage.TEST_MULTIPLE_ALLOC_PAGE);
1066: t_util.t_commit(t);
1067: t.close();
1068: }
1069:
1070: PASS("AllocMTest1");
1071: } else {
1072: REPORT("AllocMTest1 cannot be run on an insane server");
1073: return;
1074: }
1075: }
1076: }
|