All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.gs.fw.common.mithra.cache.AbstractDatedTransactionalCache Maven / Gradle / Ivy

There is a newer version: 18.1.0
Show newest version
/*
 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




© 2015 - 2024 Weber Informatics LLC | Privacy Policy