com.gs.fw.common.mithra.cache.AbstractDatedTransactionalCache Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of reladomo Show documentation
Show all versions of reladomo Show documentation
Reladomo is an object-relational mapping framework.
/*
Copyright 2016 Goldman Sachs.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
package com.gs.fw.common.mithra.cache;
import com.gs.collections.impl.set.mutable.UnifiedSet;
import com.gs.fw.common.mithra.*;
import com.gs.fw.common.mithra.behavior.state.DatedPersistenceState;
import com.gs.fw.common.mithra.cache.offheap.OffHeapDataStorage;
import com.gs.fw.common.mithra.extractor.Extractor;
import com.gs.fw.common.mithra.finder.ObjectWithMapperStack;
import com.gs.fw.common.mithra.finder.asofop.AsOfOperation;
import com.gs.fw.common.mithra.attribute.AsOfAttribute;
import com.gs.fw.common.mithra.attribute.Attribute;
import com.gs.fw.common.mithra.attribute.update.AttributeUpdateWrapper;
import com.gs.fw.common.mithra.behavior.TemporalContainer;
import com.gs.fw.common.mithra.behavior.txparticipation.TxParticipationMode;
import com.gs.fw.common.mithra.transaction.MithraDatedObjectPersister;
import com.gs.fw.common.mithra.transaction.TransactionLocal;
import java.sql.Timestamp;
import com.gs.collections.impl.list.mutable.FastList;
import com.gs.fw.common.mithra.util.ListFactory;
import java.util.Iterator;
import java.util.List;
public abstract class AbstractDatedTransactionalCache extends AbstractDatedCache
{
private TransactionLocal containerIndexTxLocal = new TransactionLocal();
private static final TransactionalDataContainerUnderlyingObjectGetter CONTAINER_UNDERLYING_OBJECT_GETTER = new TransactionalDataContainerUnderlyingObjectGetter();
protected AbstractDatedTransactionalCache(Attribute[] nonDatedPkAttributes, AsOfAttribute[] asOfAttributes,
MithraDatedObjectFactory factory, Attribute[] immutableAttributes, long timeToLive, long relationshipTimeToLive, OffHeapDataStorage dataStorage)
{
super(nonDatedPkAttributes, asOfAttributes, factory, immutableAttributes, timeToLive, relationshipTimeToLive, dataStorage);
this.setPersistedState(DatedPersistenceState.PERSISTED);
}
@Override
public Object put(MithraObject object)
{
try
{
this.getCacheLock().acquireWriteLock();
// put the data first:
MithraTransactionalObject transactionalObject = (MithraTransactionalObject) object;
MithraDataObject data = transactionalObject.zGetTxDataForRead();
int nonPkHashCode = this.getNonDatedPkHashCode(data);
this.addToIndiciesWithoutCopyInTransaction(data, nonPkHashCode);
return this.getUniqueConcurrentDatedObjectIndex().put(object, nonPkHashCode, true);
}
finally
{
this.getCacheLock().release();
}
}
/* unsynchronized */
protected MithraDataObject addToIndiciesWithoutCopyInTransaction(MithraDataObject result, int nonDatedPkHashCode)
{
MithraDataObject removed = (MithraDataObject) this.getSemiUniqueDatedIndex().put(result, nonDatedPkHashCode);
if (removed != null && removed != result)
{
for (int i = 2; i < indices.length; i++)
{
indices[i].remove(removed);
}
removed.zSetDataVersion(REMOVED_VERSION);
releaseCacheData(removed);
}
for (int i = 2; i < this.indices.length; i++)
{
indices[i].put(result);
}
return result;
}
@Override
public void remove(MithraObject object)
{
MithraTransactionalObject transactionalObject = (MithraTransactionalObject) object;
MithraDataObject data = transactionalObject.zGetTxDataForRead();
data.zSetDataVersion(REMOVED_VERSION);
this.removeDatedData(data);
// we purposely don't remove this from the dated object cache, because this method
// is only called during in-place updates, which should not affect the dated object.
}
@Override
public void removeUsingData(MithraDataObject object)
{
object.zSetDataVersion(REMOVED_VERSION);
this.removeDatedData(object);
}
@Override
public void getManyDatedObjectsFromData(Object[] dataArray, int length, ObjectWithMapperStack[] asOfOpWithStacks)
{
MithraTransaction tx = MithraManagerProvider.getMithraManager().getCurrentTransaction();
if (tx == null)
{
super.getManyDatedObjectsFromData(dataArray, length, asOfOpWithStacks);
}
else
{
Timestamp[] asOfDates = this.getTempTimestamps();
for(int i=0;i= 0 && container == null && (!this.getMithraObjectPortal().getTxParticipationMode(tx).mustParticipateInTxOnRead() || isPureHome))
{
containerWasNull = true;
container = ((MithraDatedTransactionalObjectFactory) this.getFactory()).createContainer(tx);
SemiUniqueDatedIndex semiUniqueDatedIndex = this.getSemiUniqueDatedIndex();
boolean foundInCache = semiUniqueDatedIndex.addSemiUniqueToContainer(data, container);
if (!foundInCache)
{
container.setAnyData(data);
}
putContainer(container, tx);
if (isPureHome)
{
container.setInfiniteRange();
}
tx.enrollCache(this);
}
if (container != null)
{
MithraDataObject committedData = container.getCommittedDataFromDates(asOfDates);
MithraDataObject transactionalData = container.getActiveDataFromData(data);
boolean good = committedData == data || transactionalData == data;
if (!good && (!this.getMithraObjectPortal().getTxParticipationMode(tx).mustParticipateInTxOnRead() || isPureHome))
{
good = true;
container.addCommittedData(data);
committedData = data;
}
if (good)
{
MithraDatedTransactionalObject businessObject = getOrCreateBusinessObject(committedData == null ? transactionalData : committedData, asOfDates, nonPkHashCode, weak);
if (isLocked)
{
getCacheLock().release();
}
container.lockForTransaction(businessObject, transactionalData, committedData, containerWasNull);
if (isLocked)
{
getCacheLock().acquireReadLock();
}
return businessObject;
}
}
return null;
}
@Override
public void commit(MithraTransaction tx)
{
// no lock is necessary for commit
TransactionalIndex index = (TransactionalIndex) this.getSemiUniqueDatedIndex();
index.commit(tx);
Index[] indices = this.getIndices();
for(int i=2;i 0)
{
MithraManager mithraManager = MithraManagerProvider.getMithraManager();
MithraTransaction tx = mithraManager.zGetCurrentTransactionWithNoCheck();
try
{
this.getCacheLock().acquireWriteLock();
for(Iterator it = affectedIndicies.iterator();it.hasNext();)
{
TransactionalIndex index = (TransactionalIndex)it.next();
index.prepareForReindexInTransaction(object, tx);
}
updateWrapper.updateData();
for(Iterator it = affectedIndicies.iterator();it.hasNext();)
{
TransactionalIndex index = (TransactionalIndex)it.next();
index.finishForReindex(object, tx);
}
}
finally
{
this.getCacheLock().release();
}
return;
}
}
updateWrapper.updateData();
}
@Override
public void removeIgnoringTransaction(MithraObject object)
{
throw new RuntimeException("not implemented");
}
@Override
public void prepareForCommit(MithraTransaction tx)
{
// nothing to do, because preparePut is never called on this index
}
@Override
public void commitRemovedObject(MithraDataObject data)
{
try
{
this.getCacheLock().acquireWriteLock();
data.zSetDataVersion(REMOVED_VERSION);
TransactionalIndex index = (TransactionalIndex) this.getSemiUniqueDatedIndex();
MithraDataObject oldData = (MithraDataObject) index.removeUsingUnderlying(data);
if (oldData != null)
{
Index[] indices = this.getIndices();
for(int i=2;i=0 && participationMode.isOptimisticLocking())
{
transactionalData = populateContainerAndGetTransactionalData(mithraObject, data, container);
}
else
{
this.getCacheLock().release();
lock = null;
MithraDataObject committedData =
((MithraDatedObjectPersister) mithraObject.zGetPortal().getMithraObjectPersister()).enrollDatedObject(mithraObject);
if (committedData == null)
{
throw new MithraDeletedException("The object "+mithraObject.getClass().getName()+" with primary key: "+
data.zGetPrintablePrimaryKey()+" has been terminated.");
}
this.getCacheLock().acquireReadLock();
lock = Boolean.TRUE;
transactionalData = updateExistingDataIfAny(committedData, null, mithraObject);
container.addCommittedData(transactionalData);
}
putContainer(container, tx);
tx.enrollCache(this);
}
else
{
transactionalData = container.getTxDataFor(mithraObject);
if (transactionalData == null)
{
container.checkInactivated(mithraObject);
transactionalData = container.getCommitedDataFor(mithraObject);
setAsCurrentData = true;
}
if (transactionalData == null)
{
setAsCurrentData = true;
this.getCacheLock().release();
lock = null;
tx.executeBufferedOperationsForEnroll(mithraObject.zGetPortal());
MithraDataObject committedData = ((MithraDatedObjectPersister) mithraObject.zGetPortal().getMithraObjectPersister()).enrollDatedObject(mithraObject);
if (committedData == null)
{
throw new MithraDeletedException("The object "+mithraObject.getClass().getName()+" with primary key: "+
data.zGetPrintablePrimaryKey()+" has been terminated.");
}
this.getCacheLock().acquireReadLock();
lock = Boolean.TRUE;
transactionalData = updateExistingDataIfAny(committedData, null, mithraObject);
container.addCommittedData(transactionalData);
}
}
if (lock != null)
{
this.getCacheLock().release();
lock = null;
}
if (setAsCurrentData)
{
if (forWrite)
{
return container.enrollForWrite(mithraObject, transactionalData, prevState);
}
return container.enrollReadOnly(mithraObject, transactionalData, prevState);
}
else
{
return container.possiblyEnroll(mithraObject, transactionalData, null, prevState);
}
}
finally
{
if (lock != null) this.getCacheLock().release();
}
}
@Override
public boolean enrollDatedObjectForDelete(MithraDatedTransactionalObject mithraObject, DatedTransactionalState prevState, boolean forWrite)
{
this.getCacheLock().acquireReadLock();
Boolean lock = Boolean.TRUE;
try
{
MithraDataObject data = mithraObject.zGetCurrentData();
MithraTransaction tx = MithraManagerProvider.getMithraManager().getCurrentTransaction();
TemporalContainer container = getContainerForTx(data, tx);
MithraDataObject transactionalData = null;
boolean setAsCurrentData = false;
if (container == null)
{
container = ((MithraDatedTransactionalObjectFactory) this.getFactory()).createContainer(tx);
setAsCurrentData = true;
TxParticipationMode participationMode = mithraObject.zGetPortal().getTxParticipationMode(tx);
if (data.zGetDataVersion() >=0 && participationMode.isOptimisticLocking())
{
transactionalData = populateContainerAndGetTransactionalData(mithraObject, data, container);
}
else
{
transactionalData = data;
container.addCommittedData(transactionalData);
}
putContainer(container, tx);
tx.enrollCache(this);
}
else
{
transactionalData = container.getTxDataFor(mithraObject);
if (transactionalData == null)
{
container.checkInactivatedForDelete(mithraObject);
transactionalData = container.getCommitedDataFor(mithraObject);
setAsCurrentData = true;
}
if (transactionalData == null)
{
transactionalData = data;
container.addCommittedData(transactionalData);
}
}
this.getCacheLock().release();
lock = null;
if (setAsCurrentData)
{
if (forWrite)
{
return container.enrollForWrite(mithraObject, transactionalData, prevState);
}
return container.enrollReadOnly(mithraObject, transactionalData, prevState);
}
else
{
return container.possiblyEnroll(mithraObject, transactionalData, null, prevState);
}
}
finally
{
if (lock != null) this.getCacheLock().release();
}
}
private MithraDataObject populateContainerAndGetTransactionalData(MithraDatedTransactionalObject mithraObject, MithraDataObject data, TemporalContainer container)
{
MithraDataObject transactionalData;
SemiUniqueDatedIndex semiUniqueDatedIndex = this.getSemiUniqueDatedIndex();
boolean foundCachedValue = semiUniqueDatedIndex.addSemiUniqueToContainer(data, container);
if (!foundCachedValue)
{
container.addCommittedData(data);
}
transactionalData = container.getCommitedDataFor(mithraObject);
if (transactionalData == null)
{
if (foundCachedValue)
{
container.addCommittedData(data);
}
transactionalData = container.getCommitedDataFor(mithraObject);
if (transactionalData == null)
{
transactionalData = data;
}
}
return transactionalData;
}
@Override
public MithraDataObject getTransactionalDataFromData(MithraDataObject data)
{
MithraTransaction tx = MithraManagerProvider.getMithraManager().getCurrentTransaction();
this.getCacheLock().acquireReadLock();
try
{
TemporalContainer container = getContainerForTx(data, tx);
if (container != null)
{
MithraDataObject containerData = container.getActiveOrInactiveDataFromData(data);
data = checkContainerAndAddData(container, containerData, data, null);
}
else
{
throw new RuntimeException("should never get here");
}
}
finally
{
this.getCacheLock().release();
}
return data;
}
private void putContainer(TemporalContainer container, MithraTransaction tx)
{
FullUniqueIndex index = (FullUniqueIndex) this.containerIndexTxLocal.get(tx);
if (index == null)
{
index = new FullUniqueIndex("containerIndex", getNonDatedPkAttributes());
index.setUnderlyingObjectGetter(CONTAINER_UNDERLYING_OBJECT_GETTER);
this.containerIndexTxLocal.set(tx, index);
}
index.put(container);
}
private TemporalContainer getContainerForTx(MithraDataObject data, MithraTransaction tx)
{
FullUniqueIndex index = (FullUniqueIndex) this.containerIndexTxLocal.get(tx);
if (index == null)
{
return null;
}
return (TemporalContainer) index.getFromData(data);
}
@Override
public void rollbackObject(MithraObject mithraObject)
{
this.getUniqueConcurrentDatedObjectIndex().remove(mithraObject);
}
protected static class TransactionalDataContainerUnderlyingObjectGetter implements UnderlyingObjectGetter
{
public Object getUnderlyingObject(Object o)
{
TemporalContainer dataContainer = (TemporalContainer) o;
return dataContainer.getAnyData();
}
}
@Override
protected void reindexAffectedIndices(MithraDataObject data, MithraDataObject oldData, UnifiedSet affectedIndicies)
{
MithraManager mithraManager = MithraManagerProvider.getMithraManager();
MithraTransaction tx = mithraManager.zGetCurrentTransactionWithNoCheck();
if (tx == null)
{
super.reindexAffectedIndices(data, oldData, affectedIndicies);
return;
}
List prepared = FastList.newList(affectedIndicies.size());
for (Iterator it = affectedIndicies.iterator(); it.hasNext();)
{
TransactionalIndex index = (TransactionalIndex) it.next();
if (index.prepareForReindex(oldData, tx))
{
prepared.add(index);
it.remove();
}
else
{
index.removeIgnoringTransaction(oldData);
}
}
oldData.copyNonPkAttributes(data);
for (Iterator it = affectedIndicies.iterator(); it.hasNext();)
{
TransactionalIndex index = (TransactionalIndex) it.next();
index.putIgnoringTransaction(oldData, oldData, false);
}
for(int i=0;i