[jbosscache-commits] JBoss Cache SVN: r8183 - in core/trunk/src/main/java/org/jboss/cache: commands/remote and 1 other directory.

jbosscache-commits at lists.jboss.org jbosscache-commits at lists.jboss.org
Sat Aug 15 18:25:40 EDT 2009


Author: bstansberry at jboss.com
Date: 2009-08-15 18:25:40 -0400 (Sat, 15 Aug 2009)
New Revision: 8183

Modified:
   core/trunk/src/main/java/org/jboss/cache/buddyreplication/BuddyManager.java
   core/trunk/src/main/java/org/jboss/cache/commands/remote/DataGravitationCleanupCommand.java
Log:
[JBCACHE-1530] Attempt to clean defunct data backup regions if DataGravitationCleanupCommand comes in recently after the region was created

Modified: core/trunk/src/main/java/org/jboss/cache/buddyreplication/BuddyManager.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/buddyreplication/BuddyManager.java	2009-08-14 19:31:20 UTC (rev 8182)
+++ core/trunk/src/main/java/org/jboss/cache/buddyreplication/BuddyManager.java	2009-08-15 22:25:40 UTC (rev 8183)
@@ -80,6 +80,7 @@
 import java.util.Vector;
 import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.TimeUnit;
@@ -175,6 +176,8 @@
    private boolean receivedBuddyInfo;
    private DataContainer dataContainer;
    private BuddyFqnTransformer buddyFqnTransformer;
+   
+   private ConcurrentMap<String, Set<DefunctDataHistory>> defunctDataHistory = new ConcurrentHashMap<String, Set<DefunctDataHistory>>();
 
    public BuddyManager()
    {
@@ -713,6 +716,50 @@
       }
       return owners;
    }
+   
+   public List<Fqn<?>> getNewlyDeadBackupFqns(Fqn<?> backupFqn)
+   {
+      if (buddyFqnTransformer.isDeadBackupFqn(backupFqn))
+      {
+         return null;
+      }
+      
+      if (!buddyFqnTransformer.isBackupFqn(backupFqn) || backupFqn.size() < BUDDY_BACKUP_SUBTREE_FQN.size() + 2)
+      {
+         return null;
+      }
+      
+      List<Fqn<?>> result = null;
+      String owner = (String) backupFqn.get(BUDDY_BACKUP_SUBTREE_FQN.size());
+      Set<DefunctDataHistory> historySet = defunctDataHistory.get(owner);
+      if (historySet != null)
+      {         
+         Fqn<?> coreFqn = null;
+         for (Iterator<DefunctDataHistory> it = historySet.iterator(); it.hasNext(); )
+         {
+            DefunctDataHistory gen = it.next();
+            if (gen.isStale())
+            {
+               it.remove();
+            }
+            else
+            {
+               if (result == null)
+               {
+                  result = new ArrayList<Fqn<?>>();
+               }
+               if (coreFqn == null)
+               {
+                  coreFqn = buddyFqnTransformer.getActualFqn(backupFqn);
+               }
+               Fqn<?> base = Fqn.fromRelativeElements(BUDDY_BACKUP_SUBTREE_FQN, gen.owner, Integer.valueOf(gen.generation));
+               result.add(Fqn.fromRelativeFqn(base, coreFqn));
+            }
+         }
+      }
+      
+      return result;
+   }
 
    // -------------- static util methods ------------------
 
@@ -1102,15 +1149,29 @@
    {
       Fqn defunctBackupRootFqn = getDefunctBackupRootFqn(dataOwner);
 
-      if (trace) log.trace("Migrating defunct data.  Backup root is " + backupRoot);
+      if (log.isDebugEnabled()) log.debug("Migrating defunct data.  Backup root is " + backupRoot + ". New backup root is " + defunctBackupRootFqn);
       if (trace) log.trace("Children of backup root are " + backupRoot.getChildren());
 
+      String ownerName = buddyFqnTransformer.getGroupNameFromAddress(dataOwner);
+      
+      Set<DefunctDataHistory> newHistorySet = new ConcurrentHashSet<DefunctDataHistory>();
+      Set<DefunctDataHistory> historySet = defunctDataHistory.putIfAbsent(ownerName, newHistorySet);
+      if (historySet == null)
+      {
+         historySet = newHistorySet;
+      }
+      
+      DefunctDataHistory history = new DefunctDataHistory(ownerName, (Integer) defunctBackupRootFqn.getLastElement(), System.currentTimeMillis());
+      historySet.add(history);
+      
       for (Object child : backupRoot.getChildren())
       {
          Fqn childFqn = ((Node) child).getFqn();
          cache.getInvocationContext().getOptionOverrides().setCacheModeLocal(true);
          cache.move(childFqn, defunctBackupRootFqn);
       }
+      
+      history.recordDataMoved();
 
       cache.getInvocationContext().getOptionOverrides().setCacheModeLocal(true);
       backupRoot.getParentDirect().removeChild(backupRoot.getFqn().getLastElement());
@@ -1323,4 +1384,36 @@
    {
       return buddyGroupsIParticipateIn.toString();
    }
+   
+   private class DefunctDataHistory
+   {
+      private final String owner;
+      private final int generation;
+      private final long timestamp;
+      private long dataMoved;
+      private long moveElapsedTime;
+      
+      private DefunctDataHistory(String owner, int generation, long timestamp)
+      {
+         this.owner = owner;
+         this.generation = generation;
+         this.timestamp = timestamp;
+      }
+      
+      private void recordDataMoved()
+      {
+         this.dataMoved = System.currentTimeMillis();
+         this.moveElapsedTime = this.dataMoved - this.timestamp;
+      }
+      
+      private boolean isStale()
+      {
+         if (dataMoved == 0)
+            return false;
+         
+         long max = Math.max(BuddyManager.this.configuration.getLockAcquisitionTimeout(), 60000);
+         max = max + moveElapsedTime;
+         return System.currentTimeMillis() - max < dataMoved;
+      }
+   }
 }
\ No newline at end of file

Modified: core/trunk/src/main/java/org/jboss/cache/commands/remote/DataGravitationCleanupCommand.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/commands/remote/DataGravitationCleanupCommand.java	2009-08-14 19:31:20 UTC (rev 8182)
+++ core/trunk/src/main/java/org/jboss/cache/commands/remote/DataGravitationCleanupCommand.java	2009-08-15 22:25:40 UTC (rev 8183)
@@ -105,20 +105,23 @@
             Object result = executeRemove(gtx, backup);
             if (wasNodeRemoved(result))
             {
-               // if this is a DIRECT child of a DEAD buddy backup region, then remove the empty dead region structural node.
-               Fqn deadBackupRootFqn = null;
-               if (buddyFqnTransformer.isDeadBackupFqn(backup) && buddyFqnTransformer.isDeadBackupRoot(backup.getAncestor(backup.size() - 2))
-                     && !dataContainer.hasChildren((deadBackupRootFqn = backup.getParent())))
+               cleanEmptyDeadRegion(gtx, backup);
+            }
+            else
+            {
+               // JBCACHE-1530 -- check for race where node was moved to a 
+               // xxx:DEAD region just after we returned it as a GravitateResult
+               List<Fqn<?>> deadFqns = buddyManager.getNewlyDeadBackupFqns(backup);
+               if (deadFqns != null)
                {
-                  if (trace) log.trace("Removing dead backup region " + deadBackupRootFqn);
-                  executeRemove(gtx, deadBackupRootFqn);
-
-                  // now check the grand parent and see if we are free of versions
-                  deadBackupRootFqn = deadBackupRootFqn.getParent();
-                  if (!dataContainer.hasChildren(deadBackupRootFqn))
+                  for (Fqn<?> dead : deadFqns)
                   {
-                     if (trace) log.trace("Removing dead backup region " + deadBackupRootFqn);
-                     executeRemove(gtx, deadBackupRootFqn);
+                     result = executeRemove(gtx, dead);
+                     if (wasNodeRemoved(result))
+                     {
+                        cleanEmptyDeadRegion(gtx, dead);
+                        break;
+                     }
                   }
                }
             }
@@ -138,6 +141,26 @@
       return null;
    }
 
+   private void cleanEmptyDeadRegion(GlobalTransaction gtx, Fqn backupFqn) throws Throwable
+   {
+      // if this is a DIRECT child of a DEAD buddy backup region, then remove the empty dead region structural node.
+      Fqn deadBackupRootFqn = null;
+      if (buddyFqnTransformer.isDeadBackupFqn(backupFqn) && buddyFqnTransformer.isDeadBackupRoot(backup.getAncestor(backupFqn.size() - 2))
+            && !dataContainer.hasChildren((deadBackupRootFqn = backupFqn.getParent())))
+      {
+         if (trace) log.trace("Removing dead backup region " + deadBackupRootFqn);
+         executeRemove(gtx, deadBackupRootFqn);
+
+         // now check the grand parent and see if we are free of versions
+         deadBackupRootFqn = deadBackupRootFqn.getParent();
+         if (!dataContainer.hasChildren(deadBackupRootFqn))
+         {
+            if (trace) log.trace("Removing dead backup region " + deadBackupRootFqn);
+            executeRemove(gtx, deadBackupRootFqn);
+         }
+      }
+   }
+
    /**
     * Returns true if such a node was removed.
     */



More information about the jbosscache-commits mailing list