public void persistentLoad(Object value, int txNumber) { // find appropriate body VBoxBody<E> body = this.body.getBody(txNumber); if (body.value == NOT_LOADED_VALUE) { body.value = (E) value; } }
public static <T> VBoxBody<T> makeNewBody(T value, int version, VBoxBody<T> next) { return new VBoxBody<T>(value, version, next); }
@Override public void clearPrevious() { super.clearPrevious(); // loose the reference to the owner so that it may be GCed, if needed owner = null; } }
public <T> T getBoxValue(VBox<T> vbox) { VBoxBody<T> vbody = vbox.body; /* * Due to the AOM approach we must check if the vbox.vbody is null. * In that case the object is in the compact layout and the own vbox * corresponds to most recent committed version. */ if(vbody == null) return (T) vbox; // object in compact layout. else return vbody.getBody(number).value; }
@SuppressWarnings({ "rawtypes", "unchecked" }) public static <T> VBoxBody<T> notLoadedBody() { return new VBoxBody(notLoadedValue(), 0, null); }
@Override public boolean isBoxValueLoaded(VBox vbox) { Object localValue = getLocalValue(vbox); if (localValue == VBox.NOT_LOADED_VALUE) { return false; } if (localValue != null) { return true; } VBoxBody body = vbox.body.getBody(number); return (body.value != VBox.NOT_LOADED_VALUE); }
@Override public <T> void setBoxValue(VBox<T> vbox, T value) { VBoxBody<T> body = vbox.body; if ((body != null) && (body.version == this.number)) { /* * If the head of the versioned history corresponds to the body * created by this transaction then there is no chance of this * object being reverted. */ body.value = value; } else { VBoxBody<T> newBody; if(body == null){ newBody = VBox.makeNewBody(value, number, vbox instanceof VBoxAom? new VBoxBody<T>(vbox.replicate(), 0, null) : null); }else{ newBody = VBox.makeNewBody(value, number, body); } this.vboxesWrittenBack = this.vboxesWrittenBack.cons(vbox); /* * We must prevent from concurrent reversions * The following CAS of the VBoxAom retries if the object has been reverted. */ vbox.CASbody(body, newBody); // vbox.body = newBody; } }
@Override public <T> T getBoxValue(VBox<T> vbox) { T value = null; if (specWriteSet != ReadWriteTransaction.EMPTY_MAP) { value = (T) specWriteSet.get(vbox); } if (value != null) { return (value == ReadWriteTransaction.NULL_VALUE) ? null : value; } OwnershipRecord currentOwner = vbox.inplace.orec; if (currentOwner.version > 0 && currentOwner.version <= this.number) { return vbox.body.getBody(this.number).value; } value = getLocalValue(vbox); if (value == null) { return vbox.body.getBody(this.number).value; } return (value == ReadWriteTransaction.NULL_VALUE) ? null : value; }
protected void checkValidity(ActiveTransactionsRecord record) { // we must see whether any of the boxes read by this // transaction was changed by some transaction upto the one // corresponding to the new record (newer ones don't matter) int newTxNumber = record.transactionNumber; for (Map.Entry<jvstm.VBox, VBoxBody> entry : this.bodiesRead.entrySet()) { if (entry.getKey().body.getBody(newTxNumber) != entry.getValue()) { throw new ResumeException("Transaction is no longer valid for resuming"); } } }
@Override public boolean isBoxValueLoaded(VBox vbox) { Object localValue = getLocalValue(vbox); if (localValue == VBox.NOT_LOADED_VALUE) { return false; } if (localValue != null) { return true; } VBoxBody body = vbox.body.getBody(number); return (body.value != VBox.NOT_LOADED_VALUE); }
@Override protected VBoxBody<E> CASbody(VBoxBody<E> expected, VBoxBody<E> newValue){ do{ if (UNSAFE.compareAndSwapObject(this, Offsets.bodyOffset, expected, newValue)) { expected = newValue; } else { /* * If the CAS failed the new value must already be there! * Or the object may be reverted by a concurrent GCTask and * we will retry to commit the new body. */ expected = this.body; if(expected != null) expected = expected.getBody(newValue.version); } }while(expected == null); return expected; } }
@Override protected <T> VBoxBody<T> newerVersionDetected(VBoxBody<T> body) { if (!this.boxesWritten.isEmpty() || !this.boxesWrittenInPlace.isEmpty()) { return super.newerVersionDetected(body); } else { return body.getBody(number); } }
@Override public <T> T getBoxValue(VBox<T> vbox, Object obj, String attr) { numBoxReads++; VBoxBody<T> body = vbox.body.getBody(number); if (body.value == VBox.NOT_LOADED_VALUE) { synchronized (body) { if (body.value == VBox.NOT_LOADED_VALUE) { vbox.reload(obj, attr); // after the reload, the same body should have a new value // if not, then something gone wrong and its better to abort if (body.value == VBox.NOT_LOADED_VALUE) { logger.error("Couldn't load the attribute {} for class {}", attr, obj.getClass().getName()); throw new VersionNotAvailableException(attr, obj); } } } } return body.value; }
public VBoxBody<?> commit(E newValue, int txNumber) { VBoxBody<E> currentHead = this.body; VBoxBody<E> existingBody = null; if (currentHead != null) { existingBody = currentHead.getBody(txNumber); // Commented by FMC@17-09-2012 => it causes a crash in JVM for // transactional classes that inherit fom the VBox and loaded // during the bootstrap. // assert(existingBody == null || existingBody.version <= txNumber); } if (existingBody == null || existingBody.version < txNumber) { VBoxBody<E> newBody = makeNewBody(newValue, txNumber, currentHead); existingBody = CASbody(currentHead, newBody); } // return the existingBody, regardless of whether the CAS succeeded return existingBody; }
@Override public <T> T getBoxValue(VBox<T> vbox, Object obj, String attr) { numBoxReads++; T value = getLocalValue(vbox); if (value == null) { // no local value for the box VBoxBody<T> body = vbox.body.getBody(number); if (body.value == VBox.NOT_LOADED_VALUE) { synchronized (body) { if (body.value == VBox.NOT_LOADED_VALUE) { vbox.reload(obj, attr); // after the reload, the same body should have a new // value // if not, then something gone wrong and its better to // abort if (body.value == VBox.NOT_LOADED_VALUE) { logger.error("Couldn't load the attribute {} for class {}", attr, obj.getClass()); throw new VersionNotAvailableException(attr, obj); } } } } if (bodiesRead == EMPTY_MAP) { bodiesRead = new HashMap<jvstm.VBox, VBoxBody>(); } bodiesRead.put(vbox, body); value = body.value; } return (value == NULL_VALUE) ? null : value; }
protected VBoxBody<E> CASbody(VBoxBody<E> expected, VBoxBody<E> newValue) { /* In the pure JVSTM the CAS can only fail because another thread already committed this value. However, when used together with Fenix Framework, it is possible that the body changes because of reloads. We identify this by testing whether our commit did make it (this.body.version must be >= newValue.version). If not, we retry the CAS.*/ while (true) { if (UNSAFE.compareAndSwapObject(this, Offsets.bodyOffset, expected, newValue)) { return newValue; } else { // if the CAS failed the new value must already be there unless FenixFramework was doing a reload! // update expected expected = this.body; if (expected.version < newValue.version) { // update the tail newValue = makeNewBody(newValue.value, newValue.version, expected); // retry continue; } else { return this.body.getBody(newValue.version); } } } }