package pt.ist.fenixframework.pstm; import jvstm.VBoxBody; import pt.ist.fenixframework.DomainObject; // This version of the VBox exists only because the special needs of // a RelationList which holds a SoftReference to its VBox. // For further explanations see the comment on the class SpecialBody at the end of this file class SoftReferencedVBox<E> extends ReferenceBox<E> { public SoftReferencedVBox(DomainObject ownerObj, String slotName) { super(ownerObj, slotName); } public SoftReferencedVBox(DomainObject ownerObj, String slotName, E initial) { super(ownerObj, slotName, initial); } protected SoftReferencedVBox(DomainObject ownerObj, String slotName, VBoxBody<E> body) { super(ownerObj, slotName, body); } @Override public VBoxBody commit(E newValue, int txNumber) { // see comment on the class SpecialBody at the end of this file VBoxBody<E> newBody = new SpecialBody(newValue, txNumber, this.body, this); this.body = newBody; return newBody; } public static <T> VBox<T> makeNew(DomainObject ownerObj, String slotName, boolean allocateOnly) { if (allocateOnly) { // when a box is allocated, it is safe // to say that the version number is 0 return new SoftReferencedVBox<T>(ownerObj, slotName, makeNewBody((T)NOT_LOADED_VALUE, 0, null)); } else { return new SoftReferencedVBox<T>(ownerObj, slotName); } } /* * This SpecialBody class is a hack that will eventually disappear. * It is a simple extension of a MultiVersionBoxBody so that it holds a * strong reference to the box which is owning it. Instances of this class * are created only during the processing of an AlientTransaction * (see TransactionChangeLogs) when a new version is added to a RelationList. * Because RelationLists use a SoftReference to keep the VBox (so that the * bi-directional relations do not prevent the GC from working), it could happen * that the VBox of a RelationList got GCed after the processing of an AlientTransaction * but before older running transactions finished. If meanwhile a more recent transaction * accessed the RelationList, it would load its value and associate it with version 0, which * is wrong. So, until the AlientTransaction gets cleaned up (see the * TransactionChangeLogs.cleanOldAlienTxs method), we must prevent that the VBox be GCed. * This class ensures it, because the AlientTransaction keeps strong a reference to an instance of * this class which has also a strong reference to the VBox. * Finally, when the cleanOldAlienTxs method runs and calls the freeResources on the AlienTransaction, * it calls the clearPrevious method of each body, which, in this case, also removes the reference to * the VBox. * * It's a *little* bit confusing, I know, but... */ private static class SpecialBody<E> extends VBoxBody<E> { private VBox owner; SpecialBody(E value, int version, VBoxBody<E> next, VBox owner) { super(value, version, next); this.owner = owner; } public void clearPrevious() { super.clearPrevious(); // loose the reference to the owner so that it may be GCed, if needed owner = null; } } }