/* * INESC-ID, Instituto de Engenharia de Sistemas e Computadores Investigação e Desevolvimento em Lisboa * Copyright 2013 INESC-ID and/or its affiliates and other * contributors as indicated by the @author tags. All rights reserved. * See the copyright.txt in the distribution for a full listing of * individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 3.0 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.infinispan.container.gmu; import org.infinispan.container.EntryFactoryImpl; import org.infinispan.container.entries.InternalCacheEntry; import org.infinispan.container.entries.MVCCEntry; import org.infinispan.container.entries.NullMarkerEntry; import org.infinispan.container.entries.NullMarkerEntryForRemoval; import org.infinispan.container.entries.SerializableEntry; import org.infinispan.container.entries.gmu.InternalGMUCacheEntry; import org.infinispan.container.entries.gmu.InternalGMUNullCacheEntry; import org.infinispan.container.entries.gmu.InternalGMUValueCacheEntry; import org.infinispan.container.versioning.EntryVersion; import org.infinispan.container.versioning.VersionGenerator; import org.infinispan.container.versioning.gmu.GMUVersionGenerator; import org.infinispan.context.InvocationContext; import org.infinispan.context.SingleKeyNonTxInvocationContext; import org.infinispan.context.impl.TxInvocationContext; import org.infinispan.factories.annotations.Inject; import org.infinispan.transaction.gmu.CommitLog; import org.infinispan.util.logging.Log; import org.infinispan.util.logging.LogFactory; import static org.infinispan.transaction.gmu.GMUHelper.toGMUVersionGenerator; import static org.infinispan.transaction.gmu.GMUHelper.toInternalGMUCacheEntry; /** * @author Pedro Ruivo * @author Sebastiano Peluso * @since 5.2 */ public class GMUEntryFactoryImpl extends EntryFactoryImpl { private static final Log log = LogFactory.getLog(GMUEntryFactoryImpl.class); private CommitLog commitLog; private GMUVersionGenerator gmuVersionGenerator; public static InternalGMUCacheEntry wrap(Object key, InternalCacheEntry entry, boolean mostRecent, EntryVersion maxTxVersion, EntryVersion creationVersion, EntryVersion maxValidVersion) { if (entry == null || entry.isNull()) { return new InternalGMUNullCacheEntry(key, (entry == null ? null : entry.getVersion()), maxTxVersion, mostRecent, creationVersion, maxValidVersion); } return new InternalGMUValueCacheEntry(entry, maxTxVersion, mostRecent, creationVersion, maxValidVersion); } @Inject public void injectDependencies(CommitLog commitLog, VersionGenerator versionGenerator) { this.commitLog = commitLog; this.gmuVersionGenerator = toGMUVersionGenerator(versionGenerator); } public void start() { useRepeatableRead = false; localModeWriteSkewCheck = false; } @Override protected MVCCEntry createWrappedEntry(Object key, Object value, EntryVersion version, boolean isForInsert, boolean forRemoval, long lifespan) { if (value == null && !isForInsert) { return forRemoval ? new NullMarkerEntryForRemoval(key, version) : NullMarkerEntry.getInstance(); } return new SerializableEntry(key, value, lifespan, version); } @Override protected InternalCacheEntry getFromContainer(Object key, InvocationContext context) { boolean singleRead = context instanceof SingleKeyNonTxInvocationContext; boolean remotePrepare = !context.isOriginLocal() && context.isInTxScope(); boolean remoteRead = !context.isOriginLocal() && !context.isInTxScope(); EntryVersion versionToRead; if (singleRead || remotePrepare) { //read the most recent version //in the prepare, the value does not matter (it will be written or it is not read) // and the version does not matter either (it will be overwritten) versionToRead = null; } else { versionToRead = context.calculateVersionToRead(gmuVersionGenerator); } boolean hasAlreadyReadFromThisNode = context.hasAlreadyReadOnThisNode(); if (context.isInTxScope() && context.isOriginLocal() && !context.hasAlreadyReadOnThisNode()) { //firs read on the local node for a transaction. ensure the min version EntryVersion transactionVersion = ((TxInvocationContext) context).getTransactionVersion(); try { commitLog.waitForVersion(transactionVersion, -1); } catch (InterruptedException e) { //ignore... } } EntryVersion maxVersionToRead = hasAlreadyReadFromThisNode ? versionToRead : commitLog.getAvailableVersionLessThan(versionToRead); EntryVersion mostRecentCommitLogVersion = commitLog.getCurrentVersion(); InternalGMUCacheEntry entry = toInternalGMUCacheEntry(container.get(key, maxVersionToRead)); if (remoteRead) { if (entry.getMaximumValidVersion() == null) { entry.setMaximumValidVersion(mostRecentCommitLogVersion); } else { entry.setMaximumValidVersion(commitLog.getEntry(entry.getMaximumValidVersion())); } if (entry.getCreationVersion() == null) { entry.setCreationVersion(commitLog.getOldestVersion()); } else { entry.setCreationVersion(commitLog.getEntry(entry.getCreationVersion())); } } context.addKeyReadInCommand(key, entry); if (log.isTraceEnabled()) { log.tracef("Retrieved from container %s", entry); } return entry.getInternalCacheEntry(); } }