[jbosscache-commits] JBoss Cache SVN: r6864 - in core/branches/flat/src/main/java/org/jboss/starobrno: mvcc and 1 other directory.
jbosscache-commits at lists.jboss.org
jbosscache-commits at lists.jboss.org
Wed Oct 8 07:14:14 EDT 2008
Author: manik.surtani at jboss.com
Date: 2008-10-08 07:14:14 -0400 (Wed, 08 Oct 2008)
New Revision: 6864
Added:
core/branches/flat/src/main/java/org/jboss/starobrno/factories/EntryFactory.java
core/branches/flat/src/main/java/org/jboss/starobrno/factories/EntryFactoryImpl.java
core/branches/flat/src/main/java/org/jboss/starobrno/mvcc/MVCCEntryWrapper.java
Log:
Updated factory + entry wrapper
Added: core/branches/flat/src/main/java/org/jboss/starobrno/factories/EntryFactory.java
===================================================================
--- core/branches/flat/src/main/java/org/jboss/starobrno/factories/EntryFactory.java (rev 0)
+++ core/branches/flat/src/main/java/org/jboss/starobrno/factories/EntryFactory.java 2008-10-08 11:14:14 UTC (rev 6864)
@@ -0,0 +1,39 @@
+/*
+ * 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.jboss.starobrno.factories;
+
+import org.jboss.starobrno.mvcc.MVCCEntry;
+
+import java.util.Map.Entry;
+
+/**
+ * // TODO: MANIK: Document this
+ *
+ * @author Manik Surtani (<a href="mailto:manik at jboss.org">manik at jboss.org</a>)
+ * @since 3.0
+ */
+public interface EntryFactory
+{
+ Entry createEntry(Object key, Object value, boolean putInContainer);
+
+ MVCCEntry createWrappedEntry(Entry entry);
+}
Added: core/branches/flat/src/main/java/org/jboss/starobrno/factories/EntryFactoryImpl.java
===================================================================
--- core/branches/flat/src/main/java/org/jboss/starobrno/factories/EntryFactoryImpl.java (rev 0)
+++ core/branches/flat/src/main/java/org/jboss/starobrno/factories/EntryFactoryImpl.java 2008-10-08 11:14:14 UTC (rev 6864)
@@ -0,0 +1,78 @@
+/*
+ * 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.jboss.starobrno.factories;
+
+import org.jboss.cache.config.Configuration;
+import org.jboss.cache.factories.annotations.Inject;
+import org.jboss.cache.factories.annotations.Start;
+import org.jboss.cache.lock.IsolationLevel;
+import org.jboss.starobrno.DataContainer;
+import org.jboss.starobrno.mvcc.EntryImpl;
+import org.jboss.starobrno.mvcc.MVCCEntry;
+import org.jboss.starobrno.mvcc.NullMarkerEntry;
+import org.jboss.starobrno.mvcc.ReadCommittedEntry;
+import org.jboss.starobrno.mvcc.RepeatableReadEntry;
+
+import java.util.Map.Entry;
+
+/**
+ * // TODO: MANIK: Document this
+ *
+ * @author Manik Surtani (<a href="mailto:manik at jboss.org">manik at jboss.org</a>)
+ * @since 3.0
+ */
+public class EntryFactoryImpl implements EntryFactory
+{
+ private boolean useRepeatableRead;
+ private static final NullMarkerEntry NULL_MARKER = new NullMarkerEntry();
+ private DataContainer dataContainer;
+ private Configuration configuration;
+
+ @Inject
+ public void injectDependencies(Configuration configuration,
+ DataContainer dataContainer)
+ {
+ this.dataContainer = dataContainer;
+ this.configuration = configuration;
+ }
+
+ @Start
+ public void init()
+ {
+ useRepeatableRead = configuration.getIsolationLevel() == IsolationLevel.REPEATABLE_READ;
+ }
+
+ public Entry createEntry(Object key, Object value, boolean putInContainer)
+ {
+ Entry e = new EntryImpl(key, value);
+ if (putInContainer) dataContainer.putEntry(e);
+ return e;
+ }
+
+ public MVCCEntry createWrappedEntry(Entry entry)
+ {
+ if (entry == null) return useRepeatableRead ? NULL_MARKER : null;
+
+ MVCCEntry mvccEntry = useRepeatableRead ? new RepeatableReadEntry(entry) : new ReadCommittedEntry(entry);
+ return mvccEntry;
+ }
+}
Added: core/branches/flat/src/main/java/org/jboss/starobrno/mvcc/MVCCEntryWrapper.java
===================================================================
--- core/branches/flat/src/main/java/org/jboss/starobrno/mvcc/MVCCEntryWrapper.java (rev 0)
+++ core/branches/flat/src/main/java/org/jboss/starobrno/mvcc/MVCCEntryWrapper.java 2008-10-08 11:14:14 UTC (rev 6864)
@@ -0,0 +1,183 @@
+/*
+ * 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.jboss.starobrno.mvcc;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.jboss.cache.config.Configuration;
+import org.jboss.cache.factories.annotations.Inject;
+import org.jboss.cache.factories.annotations.Start;
+import org.jboss.cache.lock.TimeoutException;
+import org.jboss.starobrno.DataContainer;
+import org.jboss.starobrno.context.InvocationContext;
+import org.jboss.starobrno.factories.EntryFactory;
+import org.jboss.starobrno.lock.LockManager;
+
+import java.util.Map.Entry;
+
+/**
+ * Wraps mvcc entries.
+ *
+ * @author Manik Surtani (<a href="mailto:manik at jboss.org">manik at jboss.org</a>)
+ * @since 3.0
+ */
+public class MVCCEntryWrapper
+{
+ DataContainer container;
+ boolean writeSkewCheck;
+ LockManager lockManager;
+ Configuration configuration;
+ long defaultLockAcquisitionTimeout;
+ EntryFactory entryFactory;
+
+ private static final Log log = LogFactory.getLog(MVCCEntryWrapper.class);
+ private static final boolean trace = log.isTraceEnabled();
+
+
+ @Inject
+ public void injectDependencies(DataContainer dataContainer, LockManager lockManager, Configuration configuration, EntryFactory entryFactory)
+ {
+ this.container = dataContainer;
+ this.configuration = configuration;
+ this.lockManager = lockManager;
+ this.entryFactory = entryFactory;
+ }
+
+ @Start
+ public void start()
+ {
+ defaultLockAcquisitionTimeout = configuration.getLockAcquisitionTimeout();
+ writeSkewCheck = configuration.isWriteSkewCheck();
+ }
+
+ public MVCCEntry wrapEntryForReading(InvocationContext ctx, Object key, boolean putInContext) throws InterruptedException
+ {
+ return wrapEntryForReading(ctx, key, putInContext, false);
+ }
+
+ public MVCCEntry wrapEntryForReading(InvocationContext ctx, Object key, boolean putInContext, boolean forceWriteLock) throws InterruptedException
+ {
+ // TODO: Do we need to wrap for reading if we are not in a TX?
+ // TODO: Also, do we need to wrap for reading even IN a TX if we are using read-committed?
+
+ MVCCEntry mvccEntry;
+ if (forceWriteLock)
+ {
+ if (trace) log.trace("Forcing lock on reading key " + key);
+ return wrapEntryForWriting(ctx, key, false, false);
+ }
+ else if ((mvccEntry = ctx.lookupEntry(key)) == null)
+ {
+ if (trace) log.trace("Key " + key + " is not in context, fetching from container.");
+ // simple implementation. Peek the node, wrap it, put wrapped node in the context.
+ Entry entry = container.getEntry(key);
+ mvccEntry = entryFactory.createWrappedEntry(entry);
+ if (mvccEntry != null && putInContext) ctx.putLookedUpEntry(mvccEntry);
+ return mvccEntry;
+ }
+ else
+ {
+ if (trace) log.trace("Key " + key + " is already in context.");
+ return mvccEntry;
+ }
+ }
+
+ public MVCCEntry wrapEntryForWriting(InvocationContext ctx, Object key, boolean createIfAbsent, boolean forceLockIfAbsent) throws InterruptedException
+ {
+ MVCCEntry mvccEntry = ctx.lookupEntry(key);
+ if (createIfAbsent && mvccEntry != null && mvccEntry.isNullEntry()) mvccEntry = null;
+ if (mvccEntry != null) // exists in context! Just acquire lock if needed, and wrap.
+ {
+ // acquire lock if needed
+ if (acquireLock(ctx, key))
+ {
+ // create a copy of the underlying node
+ mvccEntry.copyForUpdate(container, writeSkewCheck);
+ }
+ if (trace) log.trace("Retrieving wrapped node " + key);
+ if (mvccEntry.isDeleted() && createIfAbsent)
+ {
+ if (trace) log.trace("Node is deleted in current scope. Need to un-delete.");
+ mvccEntry.setDeleted(false);
+ mvccEntry.setValid(true);
+ }
+ }
+ else
+ {
+ // else, fetch from dataContainer.
+ Entry entry = container.getEntry(key);
+ if (entry != null)
+ {
+ // exists in cache! Just acquire lock if needed, and wrap.
+ // do we need a lock?
+ boolean needToCopy = false;
+ if (acquireLock(ctx, key)) needToCopy = true;
+ mvccEntry = entryFactory.createWrappedEntry(entry);
+ ctx.putLookedUpEntry(mvccEntry);
+ if (needToCopy) mvccEntry.copyForUpdate(container, writeSkewCheck);
+ }
+ else if (createIfAbsent) // else, do we need to create one?
+ {
+ // now to lock and create the node. Lock first to prevent concurrent creation!
+ acquireLock(ctx, key);
+ entry = entryFactory.createEntry(key, null, true);
+ mvccEntry = entryFactory.createWrappedEntry(entry);
+ mvccEntry.setCreated(true);
+ ctx.putLookedUpEntry(mvccEntry);
+ mvccEntry.copyForUpdate(container, writeSkewCheck);
+ }
+ }
+
+ // see if we need to force the lock on nonexistent entries.
+ if (mvccEntry == null && forceLockIfAbsent) acquireLock(ctx, key);
+
+ return mvccEntry;
+ }
+
+ /**
+ * Attempts to lock a node if the lock isn't already held in the current scope, and records the lock in the context.
+ *
+ * @param ctx context
+ * @param fqn Fqn 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.jboss.cache.lock.TimeoutException
+ * if we are unable to acquire the lock after a specified timeout.
+ */
+ private 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 Fqn 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.
+ if (!ctx.hasLockedKey(key))
+ {
+ if (!lockManager.lockAndRecord(key, ctx))
+ {
+ Object owner = lockManager.getOwner(key);
+ throw new TimeoutException("Unable to acquire lock on key [" + key + "] after [" + ctx.getLockAcquisitionTimeout(defaultLockAcquisitionTimeout) + "] milliseconds for requestor [" + lockManager.getLockOwner(ctx) + "]! Lock held by [" + owner + "]");
+ }
+ return true;
+ }
+ return false;
+ }
+}
More information about the jbosscache-commits
mailing list