package jvstm.test.point.utests.gc; import junit.framework.Assert; import jvstm.ActiveTransactionsRecord; import jvstm.Transaction; import jvstm.VBox; import jvstm.gc.TxContext; import jvstm.test.point.core.Point; import jvstm.test.point.core.PointFactory; import jvstm.test.point.core.PointFields; import org.junit.Before; import org.junit.Test; /** * This is an abstract class that defines the entry points for several unit tests * that checks the correct functioning of the versioned boxes GC. * For each specialization of Point<T> we should provide the corresponding factory and * the unit test, which inherits from this class TestPoint<T> passing to the constructor * the concrete PointFactory<T> instance. * * !!!! This test must run with the GC disabled: * -Djvstm.aom.reversion.disabled=true * * @author Fernando Miguel Carvalho */ public abstract class AomGcTest<T extends Number>{ protected final PointFactory<T> pointFac; public AomGcTest(PointFactory<T> pointFac) { this.pointFac = pointFac; } @Before public void setUp(){ TxContext currentCtx = Transaction.allTxContexts; while (currentCtx != null) { currentCtx.inCommitAndBegin = false; currentCtx.oldestRequiredVersion = null; currentCtx = currentCtx.next(); } Transaction.gcTask.runGc(); } @Test public void testTwoReversions(){ int trxNumber = Transaction.mostRecentCommittedRecord.transactionNumber; int nrOfTries = ActiveTransactionsRecord.nrOfTries; int nrOfReversions = ActiveTransactionsRecord.nrOfReversions; Point<T> p = pointFac.make(7, 9); PointFields<T> fields = new PointFields<T>((Class<T>) p.getClass()); // The factory instantiates a Point object and the // constructor does not invoke any barrier, so the // Point p must remain in the compact layout. Assert.assertSame(null, ((VBox) p).body); // The following update will create an Inevitable transaction // to perform the write operation in the Point coordinates and // it will be extended. p.setX(p.getX().intValue() + 1); // the get/set properties perform STM barriers. Assert.assertNotSame(null, ((VBox) p).body); Assert.assertEquals(++trxNumber, ((VBox) p).body.version); Assert.assertEquals(0, ((VBox) p).body.next.version); Assert.assertEquals(8, p.getX().longValue()); // the body contains the new value Assert.assertEquals(7, fields.getX(p).longValue()); // the field contains the original value Assert.assertEquals(9, p.getY().longValue()); // the body contains the old value Assert.assertEquals(9, fields.getY(p).longValue()); // the field contains the original value // After running the GC the Point object should be reverted. // And the values of the most recent body will be copied to // the standard fields of the Point object. Transaction.gcTask.runGc(); Assert.assertSame(null, ((VBox) p).body); Assert.assertEquals(8, p.getX().longValue()); // the STM barrier reads the object in-place Assert.assertEquals(8, fields.getX(p).longValue()); // the field contains the new value Assert.assertEquals(9, p.getY().longValue()); Assert.assertEquals(9, fields.getY(p).longValue()); // The following update is made inside an explicit transaction. Transaction.begin(); p.setY(p.getY().intValue() + 1); // the get/set properties perform STM barriers. Transaction.commit(); Assert.assertEquals(++trxNumber, ((VBox) p).body.version); Assert.assertEquals(0, ((VBox) p).body.next.version); Assert.assertEquals(8, p.getX().longValue()); // the body contains the old value Assert.assertEquals(8, fields.getX(p).longValue()); // the field contains the old value Assert.assertEquals(10, p.getY().longValue()); // the body contains the new value Assert.assertEquals(9, fields.getY(p).longValue()); // the field contains the original value // After running the GC the Point object should be reverted. // And the values of the most recent body will be copied to // the standard fields of the Point object. Transaction.gcTask.runGc(); Assert.assertSame(null, ((VBox) p).body); Assert.assertEquals(8, p.getX().longValue()); // the STM barrier reads the object in-place Assert.assertEquals(8, fields.getX(p).longValue()); // the field contains the new value Assert.assertEquals(10, p.getY().longValue()); Assert.assertEquals(10, fields.getY(p).longValue()); // Check the number of reversions Assert.assertEquals(nrOfTries + 2, ActiveTransactionsRecord.nrOfTries); Assert.assertEquals(nrOfReversions + 2, ActiveTransactionsRecord.nrOfReversions); } @Test public void testOneReversion(){ int trxNumber = Transaction.mostRecentCommittedRecord.transactionNumber; int nrOfTries = ActiveTransactionsRecord.nrOfTries; int nrOfReversions = ActiveTransactionsRecord.nrOfReversions; Point<T> p = pointFac.make(7, 9); PointFields<T> fields = new PointFields<T>((Class<T>) p.getClass()); // The factory instantiates a Point object and the // constructor does not invoke any barrier, so the // Point p must remain in the compact layout. Assert.assertSame(null, ((VBox) p).body); // The following update is made inside an explicit transaction. Transaction.begin(); p.setY(p.getY().intValue() + 1); // the get/set properties perform STM barriers. Transaction.commit(); Assert.assertNotSame(null, ((VBox) p).body); // object extended Assert.assertEquals(++trxNumber, ((VBox) p).body.version); // first version 2 Assert.assertEquals(0, ((VBox) p).body.next.version); // the last one 0 Assert.assertEquals(7, p.getX().longValue()); // the body contains the original value Assert.assertEquals(7, fields.getX(p).longValue()); // the field contains the original value Assert.assertEquals(10, p.getY().longValue()); // the body contains the new value Assert.assertEquals(9, fields.getY(p).longValue()); // the field contains the original value // The following update will create an Inevitable transaction // to perform the write operation in the Point coordinates and // it will be extended. p.setX(p.getX().intValue() + 1); // the get/set properties perform STM barriers. Assert.assertNotSame(null, ((VBox) p).body); Assert.assertEquals(++trxNumber, ((VBox) p).body.version); Assert.assertEquals(trxNumber-1, ((VBox) p).body.next.version); Assert.assertEquals(0, ((VBox) p).body.next.next.version); Assert.assertEquals(8, p.getX().longValue()); // the body contains the new value Assert.assertEquals(7, fields.getX(p).longValue()); // the field contains the original value Assert.assertEquals(10, p.getY().longValue()); // the body contains the new value Assert.assertEquals(9, fields.getY(p).longValue()); // the field contains the original value // After running the GC the Point object should be reverted. // And the values of the most recent body will be copied to // the standard fields of the Point object. Transaction.gcTask.runGc(); Assert.assertSame(null, ((VBox) p).body); Assert.assertEquals(8, p.getX().longValue()); // the STM barrier reads the object in-place Assert.assertEquals(8, fields.getX(p).longValue()); // the field contains the new value Assert.assertEquals(10, p.getY().longValue()); Assert.assertEquals(10, fields.getY(p).longValue()); // Check the number of reversions Assert.assertEquals(nrOfTries + 1, ActiveTransactionsRecord.nrOfTries); Assert.assertEquals(nrOfReversions + 1, ActiveTransactionsRecord.nrOfReversions); } @Test public void testMultiplePoints(){ int trxNumber = Transaction.mostRecentCommittedRecord.transactionNumber; int nrOfTries = ActiveTransactionsRecord.nrOfTries; int nrOfReversions = ActiveTransactionsRecord.nrOfReversions; Point<T>[] p = new Point[13]; for (int i = 0; i < p.length; i++) { p[i] = pointFac.make(7, 9); } PointFields<T> fields = new PointFields<T>((Class<T>) pointFac.make(7, 9).getClass()); // The factory instantiates a Point object and the // constructor does not invoke any barrier, so the // Point p must remain in the compact layout. for (int i = 0; i < p.length; i++) { Assert.assertSame(null, ((VBox) p[i]).body); } // The following update is made inside an explicit transaction. Transaction.begin(); for (int i = 0; i < p.length; i++) { p[i].setY(p[i].getY().intValue() + 1); // the get/set properties perform STM barriers. } Transaction.commit(); ++trxNumber; for (int i = 0; i < p.length; i++) { Assert.assertNotSame(null, ((VBox) p[i]).body); // object extended Assert.assertEquals(trxNumber, ((VBox) p[i]).body.version); // first version 2 Assert.assertEquals(0, ((VBox) p[i]).body.next.version); // the last one 0 Assert.assertEquals(7, p[i].getX().longValue()); // the body contains the original value Assert.assertEquals(7, fields.getX(p[i]).longValue()); // the field contains the original value Assert.assertEquals(10, p[i].getY().longValue()); // the body contains the new value Assert.assertEquals(9, fields.getY(p[i]).longValue()); // the field contains the original value } // After running the GC the Point object should be reverted. // And the values of the most recent body will be copied to // the standard fields of the Point object. Transaction.gcTask.runGc(); for (int i = 0; i < p.length; i++) { Assert.assertSame(null, ((VBox) p[i]).body); Assert.assertEquals(7, p[i].getX().longValue()); // the STM barrier reads the object in-place Assert.assertEquals(7, fields.getX(p[i]).longValue()); // the field contains the new value Assert.assertEquals(10, p[i].getY().longValue()); Assert.assertEquals(10, fields.getY(p[i]).longValue()); } // Check the number of reversions Assert.assertEquals(nrOfTries + 13, ActiveTransactionsRecord.nrOfTries); Assert.assertEquals(nrOfReversions + 13, ActiveTransactionsRecord.nrOfReversions); } }