[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