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 <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; }
@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> 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); } } } }
existingBody = currentHead.getBody(txNumber);