[infinispan-commits] Infinispan SVN: r990 - in trunk: core/src/main/java/org/infinispan/factories and 2 other directories.
infinispan-commits at lists.jboss.org
infinispan-commits at lists.jboss.org
Fri Oct 23 10:10:13 EDT 2009
Author: mircea.markus
Date: 2009-10-23 10:10:13 -0400 (Fri, 23 Oct 2009)
New Revision: 990
Added:
trunk/core/src/main/java/org/infinispan/container/EntryFactory.java
trunk/core/src/main/java/org/infinispan/container/EntryFactoryImpl.java
Removed:
trunk/core/src/main/java/org/infinispan/factories/EntryFactory.java
trunk/core/src/main/java/org/infinispan/factories/EntryFactoryImpl.java
Modified:
trunk/core/src/main/java/org/infinispan/factories/EmptyConstructorNamedCacheFactory.java
trunk/core/src/main/java/org/infinispan/interceptors/CacheLoaderInterceptor.java
trunk/core/src/main/java/org/infinispan/interceptors/LockingInterceptor.java
trunk/lucene-directory/src/main/java/org/infinispan/lucene/InfinispanLockFactory.java
Log:
moved EntryFactory in the package
Copied: trunk/core/src/main/java/org/infinispan/container/EntryFactory.java (from rev 988, trunk/core/src/main/java/org/infinispan/factories/EntryFactory.java)
===================================================================
--- trunk/core/src/main/java/org/infinispan/container/EntryFactory.java (rev 0)
+++ trunk/core/src/main/java/org/infinispan/container/EntryFactory.java 2009-10-23 14:10:13 UTC (rev 990)
@@ -0,0 +1,55 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * by the @authors tag. 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 2.1 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;
+
+import org.infinispan.container.entries.CacheEntry;
+import org.infinispan.container.entries.MVCCEntry;
+import org.infinispan.context.InvocationContext;
+import org.infinispan.util.concurrent.TimeoutException;
+
+/**
+ * // TODO: MANIK: Document this
+ *
+ * @author Manik Surtani (<a href="mailto:manik at jboss.org">manik at jboss.org</a>)
+ * @since 4.0
+ */
+public interface EntryFactory {
+ void releaseLock(Object key);
+
+ /**
+ * Attempts to lock an entry if the lock isn't already held in the current scope, and records the lock in the
+ * context.
+ *
+ * @param ctx context
+ * @param key Key to lock
+ * @return true if a lock was needed and acquired, false if it didn't need to acquire the lock (i.e., lock was
+ * already held)
+ * @throws InterruptedException if interrupted
+ * @throws org.infinispan.util.concurrent.TimeoutException
+ * if we are unable to acquire the lock after a specified timeout.
+ */
+ boolean acquireLock(InvocationContext ctx, Object key) throws InterruptedException, TimeoutException;
+
+ MVCCEntry wrapEntryForWriting(InvocationContext ctx, Object key, boolean createIfAbsent, boolean forceLockIfAbsent, boolean alreadyLocked, boolean forRemoval) throws InterruptedException;
+
+ CacheEntry wrapEntryForReading(InvocationContext ctx, Object key) throws InterruptedException;
+}
Property changes on: trunk/core/src/main/java/org/infinispan/container/EntryFactory.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Copied: trunk/core/src/main/java/org/infinispan/container/EntryFactoryImpl.java (from rev 989, trunk/core/src/main/java/org/infinispan/factories/EntryFactoryImpl.java)
===================================================================
--- trunk/core/src/main/java/org/infinispan/container/EntryFactoryImpl.java (rev 0)
+++ trunk/core/src/main/java/org/infinispan/container/EntryFactoryImpl.java 2009-10-23 14:10:13 UTC (rev 990)
@@ -0,0 +1,238 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * by the @authors tag. 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 2.1 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;
+
+import org.infinispan.config.Configuration;
+import org.infinispan.container.entries.CacheEntry;
+import org.infinispan.container.entries.MVCCEntry;
+import org.infinispan.container.entries.NullMarkerEntry;
+import org.infinispan.container.entries.NullMarkerEntryForRemoval;
+import org.infinispan.container.entries.ReadCommittedEntry;
+import org.infinispan.container.entries.RepeatableReadEntry;
+import org.infinispan.context.Flag;
+import org.infinispan.context.InvocationContext;
+import org.infinispan.factories.annotations.Inject;
+import org.infinispan.factories.annotations.Start;
+import org.infinispan.notifications.cachelistener.CacheNotifier;
+import org.infinispan.util.Util;
+import org.infinispan.util.concurrent.IsolationLevel;
+import org.infinispan.util.concurrent.TimeoutException;
+import org.infinispan.util.concurrent.locks.LockManager;
+import org.infinispan.util.logging.Log;
+import org.infinispan.util.logging.LogFactory;
+
+public class EntryFactoryImpl implements EntryFactory {
+ private boolean useRepeatableRead;
+ DataContainer container;
+ boolean writeSkewCheck;
+ LockManager lockManager;
+ Configuration configuration;
+ CacheNotifier notifier;
+
+ private static final Log log = LogFactory.getLog(EntryFactoryImpl.class);
+ private static final boolean trace = log.isTraceEnabled();
+
+ @Inject
+ public void injectDependencies(DataContainer dataContainer, LockManager lockManager, Configuration configuration, CacheNotifier notifier) {
+ this.container = dataContainer;
+ this.configuration = configuration;
+ this.lockManager = lockManager;
+ this.notifier = notifier;
+ }
+
+ @Start
+ public void init() {
+ useRepeatableRead = configuration.getIsolationLevel() == IsolationLevel.REPEATABLE_READ;
+ writeSkewCheck = configuration.isWriteSkewCheck();
+ }
+
+ private MVCCEntry createWrappedEntry(Object key, Object value, boolean isForInsert, boolean forRemoval, long lifespan) {
+ if (value == null && !isForInsert) return useRepeatableRead ?
+ forRemoval ? new NullMarkerEntryForRemoval(key) : NullMarkerEntry.getInstance()
+ : null;
+
+ return useRepeatableRead ? new RepeatableReadEntry(key, value, lifespan) : new ReadCommittedEntry(key, value, lifespan);
+ }
+
+ public final CacheEntry wrapEntryForReading(InvocationContext ctx, Object key) throws InterruptedException {
+ CacheEntry cacheEntry;
+ if (ctx.hasFlag(Flag.FORCE_WRITE_LOCK)) {
+ if (trace) log.trace("Forcing lock on reading");
+ return wrapEntryForWriting(ctx, key, false, false, false, false);
+ } else if ((cacheEntry = ctx.lookupEntry(key)) == null) {
+ if (trace) log.trace("Key {0} is not in context, fetching from container.", key);
+ // simple implementation. Peek the entry, wrap it, put wrapped entry in the context.
+ cacheEntry = container.get(key);
+
+ // do not bother wrapping though if this is not in a tx. repeatable read etc are all meaningless unless there is a tx.
+ if (useRepeatableRead && ctx.isInTxScope()) {
+ MVCCEntry mvccEntry = cacheEntry == null ?
+ createWrappedEntry(key, null, false, false, -1) :
+ createWrappedEntry(key, cacheEntry.getValue(), false, false, cacheEntry.getLifespan());
+ if (mvccEntry != null) ctx.putLookedUpEntry(key, mvccEntry);
+ return mvccEntry;
+ }
+ // if not in transaction and repeatable read, or simply read committed (regardless of whether in TX or not), do not wrap
+ if (cacheEntry != null) ctx.putLookedUpEntry(key, cacheEntry);
+ return cacheEntry;
+ } else {
+ if (trace) log.trace("Key is already in context");
+ return cacheEntry;
+ }
+ }
+
+ public final MVCCEntry wrapEntryForWriting(InvocationContext ctx, Object key, boolean createIfAbsent, boolean forceLockIfAbsent, boolean alreadyLocked, boolean forRemoval) throws InterruptedException {
+ CacheEntry cacheEntry = ctx.lookupEntry(key);
+ MVCCEntry mvccEntry = null;
+ if (createIfAbsent && cacheEntry != null && cacheEntry.isNull()) cacheEntry = null;
+ if (cacheEntry != null) // exists in context! Just acquire lock if needed, and wrap.
+ {
+ if (trace) log.trace("Exists in context.");
+ // acquire lock if needed
+ if (alreadyLocked || acquireLock(ctx, key)) {
+
+ if (cacheEntry instanceof MVCCEntry && (!forRemoval || !(cacheEntry instanceof NullMarkerEntry))) {
+ mvccEntry = (MVCCEntry) cacheEntry;
+ } else {
+ // this is a read-only entry that needs to be copied to a proper read-write entry!!
+ mvccEntry = createWrappedEntry(key, cacheEntry.getValue(), false, forRemoval, cacheEntry.getLifespan());
+ cacheEntry = mvccEntry;
+ ctx.putLookedUpEntry(key, cacheEntry);
+ }
+
+ // create a copy of the underlying entry
+ mvccEntry.copyForUpdate(container, writeSkewCheck);
+ }
+
+ if (cacheEntry.isRemoved() && createIfAbsent) {
+ if (trace) log.trace("Entry is deleted in current scope. Need to un-delete.");
+ if (mvccEntry != cacheEntry) mvccEntry = (MVCCEntry) cacheEntry;
+ mvccEntry.setRemoved(false);
+ mvccEntry.setValid(true);
+ }
+
+ return mvccEntry;
+
+ } else {
+ // else, fetch from dataContainer.
+ cacheEntry = container.get(key);
+ if (cacheEntry != null) {
+ if (trace) log.trace("Retrieved from container.");
+ // exists in cache! Just acquire lock if needed, and wrap.
+ // do we need a lock?
+ boolean lockAcquired = acquireLock(ctx, key);
+ mvccEntry = wrapExistingEntryForWriting(ctx, key, alreadyLocked, cacheEntry, lockAcquired);
+ } else if (createIfAbsent) {
+ // this is the *only* point where new entries can be created!!
+ if (trace) log.trace("Creating new entry.");
+
+ boolean lockAcquired = false;
+ // now to lock and create the entry. Lock first to prevent concurrent creation!
+ if (!alreadyLocked) {
+ lockAcquired = acquireLock(ctx, key);
+ }
+ if (lockAcquired) {
+ //double check existance, as the prev lock owner might have created a cache entry for the same key
+ cacheEntry = container.get(key);
+ if (cacheEntry != null) {
+ mvccEntry = wrapExistingEntryForWriting(ctx, key, true, cacheEntry, lockAcquired);
+ } else {
+ mvccEntry = createAndWrapEntryForWriting(ctx, key);
+ }
+ } else {
+ mvccEntry = createAndWrapEntryForWriting(ctx, key);
+ }
+ }
+ }
+
+ // see if we need to force the lock on nonexistent entries.
+ if (mvccEntry == null && forceLockIfAbsent) {
+ // make sure we record this! Null value since this is a forced lock on the key
+ if (acquireLock(ctx, key)) ctx.putLookedUpEntry(key, null);
+ }
+
+ return mvccEntry;
+ }
+
+ private MVCCEntry createAndWrapEntryForWriting(InvocationContext ctx, Object key) {
+ MVCCEntry mvccEntry;
+ notifier.notifyCacheEntryCreated(key, true, ctx);
+ mvccEntry = createWrappedEntry(key, null, true, false, -1);
+ mvccEntry.setCreated(true);
+ ctx.putLookedUpEntry(key, mvccEntry);
+ mvccEntry.copyForUpdate(container, writeSkewCheck);
+ notifier.notifyCacheEntryCreated(key, false, ctx);
+ return mvccEntry;
+ }
+
+ private MVCCEntry wrapExistingEntryForWriting(InvocationContext ctx, Object key, boolean alreadyLocked, CacheEntry cacheEntry, boolean lockAquired) {
+ MVCCEntry mvccEntry;
+ mvccEntry = createWrappedEntry(key, cacheEntry.getValue(), false, false, cacheEntry.getLifespan());
+ ctx.putLookedUpEntry(key, mvccEntry);
+ boolean needToCopy = alreadyLocked || lockAquired || ctx.hasFlag(Flag.SKIP_LOCKING); // even if we do not acquire a lock, if skip-locking is enabled we should copy
+ if (needToCopy) mvccEntry.copyForUpdate(container, writeSkewCheck);
+ return mvccEntry;
+ }
+
+ /**
+ * Attempts to lock an entry if the lock isn't already held in the current scope, and records the lock in the
+ * context.
+ *
+ * @param ctx context
+ * @param key Key to lock
+ * @return true if a lock was needed and acquired, false if it didn't need to acquire the lock (i.e., lock was
+ * already held)
+ * @throws InterruptedException if interrupted
+ * @throws org.infinispan.util.concurrent.TimeoutException
+ * if we are unable to acquire the lock after a specified timeout.
+ */
+ public final boolean acquireLock(InvocationContext ctx, Object key) throws InterruptedException, TimeoutException {
+ // don't EVER use lockManager.isLocked() since with lock striping it may be the case that we hold the relevant
+ // lock which may be shared with another key that we have a lock for already.
+ // nothing wrong, just means that we fail to record the lock. And that is a problem.
+ // Better to check our records and lock again if necessary.
+
+ boolean shouldSkipLocking = ctx.hasFlag(Flag.SKIP_LOCKING);
+
+ if (!ctx.hasLockedKey(key) && !shouldSkipLocking) {
+ if (lockManager.lockAndRecord(key, ctx)) {
+ // successfully locked!
+ return true;
+ } else {
+ Object owner = lockManager.getOwner(key);
+ throw new TimeoutException("Unable to acquire lock after [" + Util.prettyPrintTime(getLockAcquisitionTimeout(ctx)) + "] on key [" + key + "] for requestor [" +
+ ctx.getLockOwner() + "]! Lock held by [" + owner + "]");
+ }
+ }
+
+ return false;
+ }
+
+ private long getLockAcquisitionTimeout(InvocationContext ctx) {
+ return ctx.hasFlag(Flag.ZERO_LOCK_ACQUISITION_TIMEOUT) ?
+ 0 : configuration.getLockAcquisitionTimeout();
+ }
+
+ public final void releaseLock(Object key) {
+ lockManager.unlock(key, lockManager.getOwner(key));
+ }
+}
Property changes on: trunk/core/src/main/java/org/infinispan/container/EntryFactoryImpl.java
___________________________________________________________________
Name: svn:keywords
+ Id Revision
Name: svn:eol-style
+ LF
Modified: trunk/core/src/main/java/org/infinispan/factories/EmptyConstructorNamedCacheFactory.java
===================================================================
--- trunk/core/src/main/java/org/infinispan/factories/EmptyConstructorNamedCacheFactory.java 2009-10-23 12:45:59 UTC (rev 989)
+++ trunk/core/src/main/java/org/infinispan/factories/EmptyConstructorNamedCacheFactory.java 2009-10-23 14:10:13 UTC (rev 990)
@@ -35,6 +35,7 @@
import org.infinispan.notifications.cachelistener.CacheNotifier;
import org.infinispan.transaction.TransactionLog;
import org.infinispan.util.Util;
+import org.infinispan.container.EntryFactory;
/**
* Simple factory that just uses reflection and an empty constructor of the component type.
Deleted: trunk/core/src/main/java/org/infinispan/factories/EntryFactory.java
===================================================================
--- trunk/core/src/main/java/org/infinispan/factories/EntryFactory.java 2009-10-23 12:45:59 UTC (rev 989)
+++ trunk/core/src/main/java/org/infinispan/factories/EntryFactory.java 2009-10-23 14:10:13 UTC (rev 990)
@@ -1,55 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source
- * Copyright 2008, Red Hat Middleware LLC, and individual contributors
- * by the @authors tag. 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 2.1 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.factories;
-
-import org.infinispan.container.entries.CacheEntry;
-import org.infinispan.container.entries.MVCCEntry;
-import org.infinispan.context.InvocationContext;
-import org.infinispan.util.concurrent.TimeoutException;
-
-/**
- * // TODO: MANIK: Document this
- *
- * @author Manik Surtani (<a href="mailto:manik at jboss.org">manik at jboss.org</a>)
- * @since 4.0
- */
-public interface EntryFactory {
- void releaseLock(Object key);
-
- /**
- * Attempts to lock an entry if the lock isn't already held in the current scope, and records the lock in the
- * context.
- *
- * @param ctx context
- * @param key Key to lock
- * @return true if a lock was needed and acquired, false if it didn't need to acquire the lock (i.e., lock was
- * already held)
- * @throws InterruptedException if interrupted
- * @throws org.infinispan.util.concurrent.TimeoutException
- * if we are unable to acquire the lock after a specified timeout.
- */
- boolean acquireLock(InvocationContext ctx, Object key) throws InterruptedException, TimeoutException;
-
- MVCCEntry wrapEntryForWriting(InvocationContext ctx, Object key, boolean createIfAbsent, boolean forceLockIfAbsent, boolean alreadyLocked, boolean forRemoval) throws InterruptedException;
-
- CacheEntry wrapEntryForReading(InvocationContext ctx, Object key) throws InterruptedException;
-}
Deleted: trunk/core/src/main/java/org/infinispan/factories/EntryFactoryImpl.java
===================================================================
--- trunk/core/src/main/java/org/infinispan/factories/EntryFactoryImpl.java 2009-10-23 12:45:59 UTC (rev 989)
+++ trunk/core/src/main/java/org/infinispan/factories/EntryFactoryImpl.java 2009-10-23 14:10:13 UTC (rev 990)
@@ -1,239 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source
- * Copyright 2008, Red Hat Middleware LLC, and individual contributors
- * by the @authors tag. 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 2.1 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.factories;
-
-import org.infinispan.config.Configuration;
-import org.infinispan.container.DataContainer;
-import org.infinispan.container.entries.CacheEntry;
-import org.infinispan.container.entries.MVCCEntry;
-import org.infinispan.container.entries.NullMarkerEntry;
-import org.infinispan.container.entries.NullMarkerEntryForRemoval;
-import org.infinispan.container.entries.ReadCommittedEntry;
-import org.infinispan.container.entries.RepeatableReadEntry;
-import org.infinispan.context.Flag;
-import org.infinispan.context.InvocationContext;
-import org.infinispan.factories.annotations.Inject;
-import org.infinispan.factories.annotations.Start;
-import org.infinispan.notifications.cachelistener.CacheNotifier;
-import org.infinispan.util.Util;
-import org.infinispan.util.concurrent.IsolationLevel;
-import org.infinispan.util.concurrent.TimeoutException;
-import org.infinispan.util.concurrent.locks.LockManager;
-import org.infinispan.util.logging.Log;
-import org.infinispan.util.logging.LogFactory;
-
-public class EntryFactoryImpl implements EntryFactory {
- private boolean useRepeatableRead;
- DataContainer container;
- boolean writeSkewCheck;
- LockManager lockManager;
- Configuration configuration;
- CacheNotifier notifier;
-
- private static final Log log = LogFactory.getLog(EntryFactoryImpl.class);
- private static final boolean trace = log.isTraceEnabled();
-
- @Inject
- public void injectDependencies(DataContainer dataContainer, LockManager lockManager, Configuration configuration, CacheNotifier notifier) {
- this.container = dataContainer;
- this.configuration = configuration;
- this.lockManager = lockManager;
- this.notifier = notifier;
- }
-
- @Start
- public void init() {
- useRepeatableRead = configuration.getIsolationLevel() == IsolationLevel.REPEATABLE_READ;
- writeSkewCheck = configuration.isWriteSkewCheck();
- }
-
- private MVCCEntry createWrappedEntry(Object key, Object value, boolean isForInsert, boolean forRemoval, long lifespan) {
- if (value == null && !isForInsert) return useRepeatableRead ?
- forRemoval ? new NullMarkerEntryForRemoval(key) : NullMarkerEntry.getInstance()
- : null;
-
- return useRepeatableRead ? new RepeatableReadEntry(key, value, lifespan) : new ReadCommittedEntry(key, value, lifespan);
- }
-
- public final CacheEntry wrapEntryForReading(InvocationContext ctx, Object key) throws InterruptedException {
- CacheEntry cacheEntry;
- if (ctx.hasFlag(Flag.FORCE_WRITE_LOCK)) {
- if (trace) log.trace("Forcing lock on reading");
- return wrapEntryForWriting(ctx, key, false, false, false, false);
- } else if ((cacheEntry = ctx.lookupEntry(key)) == null) {
- if (trace) log.trace("Key {0} is not in context, fetching from container.", key);
- // simple implementation. Peek the entry, wrap it, put wrapped entry in the context.
- cacheEntry = container.get(key);
-
- // do not bother wrapping though if this is not in a tx. repeatable read etc are all meaningless unless there is a tx.
- if (useRepeatableRead && ctx.isInTxScope()) {
- MVCCEntry mvccEntry = cacheEntry == null ?
- createWrappedEntry(key, null, false, false, -1) :
- createWrappedEntry(key, cacheEntry.getValue(), false, false, cacheEntry.getLifespan());
- if (mvccEntry != null) ctx.putLookedUpEntry(key, mvccEntry);
- return mvccEntry;
- }
- // if not in transaction and repeatable read, or simply read committed (regardless of whether in TX or not), do not wrap
- if (cacheEntry != null) ctx.putLookedUpEntry(key, cacheEntry);
- return cacheEntry;
- } else {
- if (trace) log.trace("Key is already in context");
- return cacheEntry;
- }
- }
-
- public final MVCCEntry wrapEntryForWriting(InvocationContext ctx, Object key, boolean createIfAbsent, boolean forceLockIfAbsent, boolean alreadyLocked, boolean forRemoval) throws InterruptedException {
- CacheEntry cacheEntry = ctx.lookupEntry(key);
- MVCCEntry mvccEntry = null;
- if (createIfAbsent && cacheEntry != null && cacheEntry.isNull()) cacheEntry = null;
- if (cacheEntry != null) // exists in context! Just acquire lock if needed, and wrap.
- {
- if (trace) log.trace("Exists in context.");
- // acquire lock if needed
- if (alreadyLocked || acquireLock(ctx, key)) {
-
- if (cacheEntry instanceof MVCCEntry && (!forRemoval || !(cacheEntry instanceof NullMarkerEntry))) {
- mvccEntry = (MVCCEntry) cacheEntry;
- } else {
- // this is a read-only entry that needs to be copied to a proper read-write entry!!
- mvccEntry = createWrappedEntry(key, cacheEntry.getValue(), false, forRemoval, cacheEntry.getLifespan());
- cacheEntry = mvccEntry;
- ctx.putLookedUpEntry(key, cacheEntry);
- }
-
- // create a copy of the underlying entry
- mvccEntry.copyForUpdate(container, writeSkewCheck);
- }
-
- if (cacheEntry.isRemoved() && createIfAbsent) {
- if (trace) log.trace("Entry is deleted in current scope. Need to un-delete.");
- if (mvccEntry != cacheEntry) mvccEntry = (MVCCEntry) cacheEntry;
- mvccEntry.setRemoved(false);
- mvccEntry.setValid(true);
- }
-
- return mvccEntry;
-
- } else {
- // else, fetch from dataContainer.
- cacheEntry = container.get(key);
- if (cacheEntry != null) {
- if (trace) log.trace("Retrieved from container.");
- // exists in cache! Just acquire lock if needed, and wrap.
- // do we need a lock?
- boolean lockAcquired = acquireLock(ctx, key);
- mvccEntry = wrapExistingEntryForWriting(ctx, key, alreadyLocked, cacheEntry, lockAcquired);
- } else if (createIfAbsent) {
- // this is the *only* point where new entries can be created!!
- if (trace) log.trace("Creating new entry.");
-
- boolean lockAcquired = false;
- // now to lock and create the entry. Lock first to prevent concurrent creation!
- if (!alreadyLocked) {
- lockAcquired = acquireLock(ctx, key);
- }
- if (lockAcquired) {
- //double check existance, as the prev lock owner might have created a cache entry for the same key
- cacheEntry = container.get(key);
- if (cacheEntry != null) {
- mvccEntry = wrapExistingEntryForWriting(ctx, key, true, cacheEntry, lockAcquired);
- } else {
- mvccEntry = createAndWrapEntryForWriting(ctx, key);
- }
- } else {
- mvccEntry = createAndWrapEntryForWriting(ctx, key);
- }
- }
- }
-
- // see if we need to force the lock on nonexistent entries.
- if (mvccEntry == null && forceLockIfAbsent) {
- // make sure we record this! Null value since this is a forced lock on the key
- if (acquireLock(ctx, key)) ctx.putLookedUpEntry(key, null);
- }
-
- return mvccEntry;
- }
-
- private MVCCEntry createAndWrapEntryForWriting(InvocationContext ctx, Object key) {
- MVCCEntry mvccEntry;
- notifier.notifyCacheEntryCreated(key, true, ctx);
- mvccEntry = createWrappedEntry(key, null, true, false, -1);
- mvccEntry.setCreated(true);
- ctx.putLookedUpEntry(key, mvccEntry);
- mvccEntry.copyForUpdate(container, writeSkewCheck);
- notifier.notifyCacheEntryCreated(key, false, ctx);
- return mvccEntry;
- }
-
- private MVCCEntry wrapExistingEntryForWriting(InvocationContext ctx, Object key, boolean alreadyLocked, CacheEntry cacheEntry, boolean lockAquired) {
- MVCCEntry mvccEntry;
- mvccEntry = createWrappedEntry(key, cacheEntry.getValue(), false, false, cacheEntry.getLifespan());
- ctx.putLookedUpEntry(key, mvccEntry);
- boolean needToCopy = alreadyLocked || lockAquired || ctx.hasFlag(Flag.SKIP_LOCKING); // even if we do not acquire a lock, if skip-locking is enabled we should copy
- if (needToCopy) mvccEntry.copyForUpdate(container, writeSkewCheck);
- return mvccEntry;
- }
-
- /**
- * Attempts to lock an entry if the lock isn't already held in the current scope, and records the lock in the
- * context.
- *
- * @param ctx context
- * @param key Key to lock
- * @return true if a lock was needed and acquired, false if it didn't need to acquire the lock (i.e., lock was
- * already held)
- * @throws InterruptedException if interrupted
- * @throws org.infinispan.util.concurrent.TimeoutException
- * if we are unable to acquire the lock after a specified timeout.
- */
- public final boolean acquireLock(InvocationContext ctx, Object key) throws InterruptedException, TimeoutException {
- // don't EVER use lockManager.isLocked() since with lock striping it may be the case that we hold the relevant
- // lock which may be shared with another key that we have a lock for already.
- // nothing wrong, just means that we fail to record the lock. And that is a problem.
- // Better to check our records and lock again if necessary.
-
- boolean shouldSkipLocking = ctx.hasFlag(Flag.SKIP_LOCKING);
-
- if (!ctx.hasLockedKey(key) && !shouldSkipLocking) {
- if (lockManager.lockAndRecord(key, ctx)) {
- // successfully locked!
- return true;
- } else {
- Object owner = lockManager.getOwner(key);
- throw new TimeoutException("Unable to acquire lock after [" + Util.prettyPrintTime(getLockAcquisitionTimeout(ctx)) + "] on key [" + key + "] for requestor [" +
- ctx.getLockOwner() + "]! Lock held by [" + owner + "]");
- }
- }
-
- return false;
- }
-
- private long getLockAcquisitionTimeout(InvocationContext ctx) {
- return ctx.hasFlag(Flag.ZERO_LOCK_ACQUISITION_TIMEOUT) ?
- 0 : configuration.getLockAcquisitionTimeout();
- }
-
- public final void releaseLock(Object key) {
- lockManager.unlock(key, lockManager.getOwner(key));
- }
-}
Modified: trunk/core/src/main/java/org/infinispan/interceptors/CacheLoaderInterceptor.java
===================================================================
--- trunk/core/src/main/java/org/infinispan/interceptors/CacheLoaderInterceptor.java 2009-10-23 12:45:59 UTC (rev 989)
+++ trunk/core/src/main/java/org/infinispan/interceptors/CacheLoaderInterceptor.java 2009-10-23 14:10:13 UTC (rev 990)
@@ -31,7 +31,7 @@
import org.infinispan.container.entries.InternalCacheEntry;
import org.infinispan.container.entries.MVCCEntry;
import org.infinispan.context.InvocationContext;
-import org.infinispan.factories.EntryFactory;
+import org.infinispan.container.EntryFactory;
import org.infinispan.factories.annotations.Inject;
import org.infinispan.factories.annotations.Start;
import org.infinispan.interceptors.base.JmxStatsCommandInterceptor;
Modified: trunk/core/src/main/java/org/infinispan/interceptors/LockingInterceptor.java
===================================================================
--- trunk/core/src/main/java/org/infinispan/interceptors/LockingInterceptor.java 2009-10-23 12:45:59 UTC (rev 989)
+++ trunk/core/src/main/java/org/infinispan/interceptors/LockingInterceptor.java 2009-10-23 14:10:13 UTC (rev 990)
@@ -34,11 +34,11 @@
import org.infinispan.commands.write.RemoveCommand;
import org.infinispan.commands.write.ReplaceCommand;
import org.infinispan.container.DataContainer;
+import org.infinispan.container.EntryFactory;
import org.infinispan.container.entries.CacheEntry;
import org.infinispan.context.Flag;
import org.infinispan.context.InvocationContext;
import org.infinispan.context.impl.TxInvocationContext;
-import org.infinispan.factories.EntryFactory;
import org.infinispan.factories.annotations.Inject;
import org.infinispan.factories.annotations.Start;
import org.infinispan.interceptors.base.CommandInterceptor;
Modified: trunk/lucene-directory/src/main/java/org/infinispan/lucene/InfinispanLockFactory.java
===================================================================
--- trunk/lucene-directory/src/main/java/org/infinispan/lucene/InfinispanLockFactory.java 2009-10-23 12:45:59 UTC (rev 989)
+++ trunk/lucene-directory/src/main/java/org/infinispan/lucene/InfinispanLockFactory.java 2009-10-23 14:10:13 UTC (rev 990)
@@ -21,21 +21,19 @@
*/
package org.infinispan.lucene;
-import java.io.IOException;
-import javax.transaction.RollbackException;
-import javax.transaction.Transaction;
-import javax.transaction.TransactionManager;
-
-import org.apache.lucene.store.Lock;
+import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.store.LockFactory;
import org.infinispan.Cache;
-import org.infinispan.CacheException;
import org.infinispan.util.logging.Log;
import org.infinispan.util.logging.LogFactory;
+import javax.transaction.TransactionManager;
+import java.io.IOException;
+
/**
* Factory for locks obtained in <code>InfinispanDirectory</code>
*
+ * @author Sanne Grinovero
* @since 4.0
* @author Lukasz Moren
* @see org.infinispan.lucene.InfinispanDirectory
@@ -44,183 +42,60 @@
public class InfinispanLockFactory extends LockFactory {
private static final Log log = LogFactory.getLog(InfinispanLockFactory.class);
+ static final String DEF_LOCK_NAME = IndexWriter.WRITE_LOCK_NAME;
- private Cache<CacheKey, Object> cache;
- private String indexName;
+ private final Cache<CacheKey, Object> cache;
+ private final String indexName;
+ private final TransactionManager tm;
+ private final InfinispanLock defLock;
public InfinispanLockFactory(Cache<CacheKey, Object> cache, String indexName) {
this.cache = cache;
this.indexName = indexName;
+// tm = cache.getAdvancedCache().getComponentRegistry().getComponent(TransactionManager.class);
+// if (tm == null) {
+// throw new CacheException(
+// "Failed looking up TransactionManager, check if any transaction manager is associated with Infinispan cache: "
+// + cache.getName());
+// }
+ tm = null;
+ defLock = new InfinispanLock(cache, indexName, DEF_LOCK_NAME, tm);
}
/**
* {@inheritDoc}
*/
- public Lock makeLock(String lockName) {
- try {
- return new InfinispanLock(cache, indexName, lockName);
- } finally {
- if (log.isTraceEnabled()) {
- log.trace("Created new lock: {0} for index {1}", lockName, indexName);
- }
+ public InfinispanLock makeLock(String lockName) {
+ InfinispanLock lock;
+ //It appears Lucene always uses the same name so we give locks
+ //having this name a special treatment:
+ if (DEF_LOCK_NAME.equals(lockName)) {
+ lock = defLock;
}
+ else {
+ // this branch is never taken with current Lucene version.
+ lock = new InfinispanLock(cache, indexName, lockName, tm);
+ }
+ if (log.isTraceEnabled()) {
+ log.trace("Lock prepared, not acquired: {0} for index {1}", lockName, indexName);
+ }
+ return lock;
}
/**
* {@inheritDoc}
*/
public void clearLock(String lockName) throws IOException {
- try {
- cache.remove(new FileCacheKey(indexName, lockName, true));
- } finally {
- if (log.isTraceEnabled()) {
- log.trace("Removed lock: {0} for index {1}", lockName, indexName);
- }
+ //Same special care as above for locks named DEF_LOCK_NAME:
+ if (DEF_LOCK_NAME.equals(lockName)) {
+ defLock.clearLock();
}
- }
-
- /**
- * Interprocess Lucene index lock
- *
- * @see org.apache.lucene.store.Directory#makeLock(String)
- */
- public static class InfinispanLock extends Lock {
-
- private static final Log log = LogFactory.getLog(InfinispanLock.class);
-
- private final Cache<CacheKey, Object> cache;
- private String lockName;
- private String indexName;
-
- final TransactionManager tm;
-
- InfinispanLock(Cache<CacheKey, Object> cache, String indexName, String lockName) {
- this.cache = cache;
- this.lockName = lockName;
- this.indexName = indexName;
-
- tm = cache.getAdvancedCache().getComponentRegistry().getComponent(TransactionManager.class);
- if (tm == null) {
- throw new CacheException(
- "Failed looking up TransactionManager, check if any transaction manager is associated with Infinispan cache: "
- + cache.getName());
- }
+ else {
+ new InfinispanLock(cache, indexName, lockName, tm).clearLock();
}
-
- /**
- * {@inheritDoc}
- */
- public boolean obtain() throws IOException {
- boolean acquired = false;
-
- synchronized (cache) {
- try {
- // begin transaction for lock obtaining
- tm.begin();
- CacheKey lock = new FileCacheKey(indexName, lockName, true);
- if (!cache.containsKey(lock)) {
- cache.put(lock, lock);
- acquired = true;
- }
- } catch (Exception e) {
- log.error("Cannot obtain lock for: " + indexName, e);
- } finally {
- try {
- if (tm.getTransaction() != null) {
- if (acquired) {
- tm.commit();
- if (log.isTraceEnabled()) {
- log.trace("Lock: {0} acquired for index: {1} ", lockName, indexName);
- }
- } else {
- tm.rollback();
- }
- }
- } catch (RollbackException e) {
- log.error("Cannot obtain lock for: " + indexName, e);
- acquired = false;
- } catch (Exception e) {
- throw new CacheException(e);
- }
- }
-
- if (acquired) {
- try {
- // begin new transaction to batch all changes, tx commited when lock is released.
- tm.begin();
- if (log.isTraceEnabled()) {
- log.trace("Batch transaction started for index: {0}", indexName);
- }
- } catch (Exception e) {
- log.error("Unable to start transaction", e);
- }
- }
- }
-
- return acquired;
+ if (log.isTraceEnabled()) {
+ log.trace("Removed lock: {0} for index {1}", lockName, indexName);
}
-
- /**
- * {@inheritDoc}
- */
- public void release() throws IOException {
- boolean removed = false;
- synchronized (cache) {
- try {
- // commit changes in batch, transaction was started when lock was acquired
- tm.commit();
- if (log.isTraceEnabled()) {
- log.trace("Batch transaction commited for index: {0}", indexName);
- }
-
- tm.begin();
- removed = cache.remove(new FileCacheKey(indexName, lockName, true)) != null;
- } catch (Exception e) {
- throw new CacheException("Unable to commit work done or release lock!", e);
- } finally {
- try {
- if (removed) {
- tm.commit();
- if (log.isTraceEnabled()) {
- log.trace("Lock: {0} removed for index: {1} ", lockName, indexName);
- }
- } else {
- tm.rollback();
- }
- } catch (Exception e) {
- throw new CacheException("Unable to release lock!", e);
- }
- }
- }
- }
-
- /**
- * {@inheritDoc}
- */
- public boolean isLocked() {
- boolean locked = false;
- synchronized (cache) {
- Transaction tx = null;
- try {
- // if there is an ongoing transaction we need to suspend it
- if ((tx = tm.getTransaction()) != null) {
- tm.suspend();
- }
- locked = cache.containsKey(new FileCacheKey(indexName, lockName, true));
- } catch (Exception e) {
- log.error("Error in suspending transaction", e);
- } finally {
- if (tx != null) {
- try {
- tm.resume(tx);
- } catch (Exception e) {
- throw new CacheException("Unable to resume suspended transaction " + tx, e);
- }
- }
- }
- }
- return locked;
- }
}
-
+
}
More information about the infinispan-commits
mailing list