You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by he...@apache.org on 2015/02/09 16:36:29 UTC

[10/22] incubator-brooklyn git commit: Partial rebind - using new explicit BrooklynObjectManagementMode

Partial rebind - using new explicit BrooklynObjectManagementMode


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/3f7d7508
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/3f7d7508
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/3f7d7508

Branch: refs/heads/master
Commit: 3f7d7508e125d751933dc40914d72441ce27381e
Parents: 0fb0c63
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Tue Feb 3 12:48:22 2015 +0000
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Fri Feb 6 22:12:13 2015 +0000

----------------------------------------------------------------------
 .../rebind/InitialFullRebindIteration.java      |   7 +-
 .../brooklyn/entity/rebind/RebindIteration.java |  75 ++++++++++-
 .../entity/rebind/RebindManagerImpl.java        |  44 -------
 .../ha/HighAvailabilityManagerImpl.java         |   8 +-
 .../internal/BrooklynObjectManagerInternal.java |  37 ++++++
 .../internal/EntityManagementSupport.java       |   2 +-
 .../internal/EntityManagerInternal.java         |  15 +--
 .../management/internal/LocalEntityManager.java |  41 +++---
 .../internal/LocalLocationManager.java          |  49 ++++---
 .../internal/LocationManagerInternal.java       |  14 +-
 .../internal/ManagementTransitionInfo.java      | 131 +++++++++++++++----
 11 files changed, 275 insertions(+), 148 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3f7d7508/core/src/main/java/brooklyn/entity/rebind/InitialFullRebindIteration.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/rebind/InitialFullRebindIteration.java b/core/src/main/java/brooklyn/entity/rebind/InitialFullRebindIteration.java
index 9b08392..e416bbc 100644
--- a/core/src/main/java/brooklyn/entity/rebind/InitialFullRebindIteration.java
+++ b/core/src/main/java/brooklyn/entity/rebind/InitialFullRebindIteration.java
@@ -33,6 +33,7 @@ import brooklyn.management.ha.ManagementNodeState;
 import brooklyn.management.internal.EntityManagerInternal;
 import brooklyn.management.internal.LocationManagerInternal;
 import brooklyn.management.internal.ManagementTransitionInfo.ManagementTransitionMode;
+import brooklyn.management.internal.ManagementTransitionInfo.BrooklynObjectManagementMode;
 import brooklyn.mementos.BrooklynMementoPersister;
 import brooklyn.util.text.Strings;
 
@@ -113,7 +114,8 @@ public class InitialFullRebindIteration extends RebindIteration {
         if (!oldLocations.isEmpty()) BrooklynLogging.log(LOG, overwritingMaster ? BrooklynLogging.LoggingLevel.WARN : BrooklynLogging.LoggingLevel.DEBUG, 
             "Destroying unused locations on rebind: "+oldLocations);
         for (String oldLocationId: oldLocations) {
-           locationManager.unmanage(locationManager.getLocation(oldLocationId), ManagementTransitionMode.REBINDING_DESTROYED); 
+           locationManager.unmanage(locationManager.getLocation(oldLocationId), ManagementTransitionMode.guessing(
+               BrooklynObjectManagementMode.MANAGED_PRIMARY, BrooklynObjectManagementMode.NONEXISTENT)); 
         }
     }
 
@@ -123,7 +125,8 @@ public class InitialFullRebindIteration extends RebindIteration {
         if (!oldEntities.isEmpty()) BrooklynLogging.log(LOG, overwritingMaster ? BrooklynLogging.LoggingLevel.WARN : BrooklynLogging.LoggingLevel.DEBUG, 
             "Destroying unused entities on rebind: "+oldEntities);
         for (String oldEntityId: oldEntities) {
-           entityManager.unmanage(entityManager.getEntity(oldEntityId), ManagementTransitionMode.REBINDING_DESTROYED); 
+           entityManager.unmanage(entityManager.getEntity(oldEntityId), ManagementTransitionMode.guessing(
+               BrooklynObjectManagementMode.MANAGED_PRIMARY, BrooklynObjectManagementMode.NONEXISTENT));
         }
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3f7d7508/core/src/main/java/brooklyn/entity/rebind/RebindIteration.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/rebind/RebindIteration.java b/core/src/main/java/brooklyn/entity/rebind/RebindIteration.java
index b4288c7..d786571 100644
--- a/core/src/main/java/brooklyn/entity/rebind/RebindIteration.java
+++ b/core/src/main/java/brooklyn/entity/rebind/RebindIteration.java
@@ -63,10 +63,12 @@ import brooklyn.location.basic.AbstractLocation;
 import brooklyn.location.basic.LocationInternal;
 import brooklyn.management.classloading.BrooklynClassLoadingContext;
 import brooklyn.management.ha.ManagementNodeState;
+import brooklyn.management.internal.BrooklynObjectManagerInternal;
 import brooklyn.management.internal.EntityManagerInternal;
 import brooklyn.management.internal.LocationManagerInternal;
 import brooklyn.management.internal.ManagementContextInternal;
 import brooklyn.management.internal.ManagementTransitionInfo.ManagementTransitionMode;
+import brooklyn.management.internal.ManagementTransitionInfo.BrooklynObjectManagementMode;
 import brooklyn.mementos.BrooklynMemento;
 import brooklyn.mementos.BrooklynMementoManifest;
 import brooklyn.mementos.BrooklynMementoManifest.EntityMementoManifest;
@@ -600,8 +602,7 @@ public abstract class RebindIteration {
         LocationManagerInternal locationManager = (LocationManagerInternal)managementContext.getLocationManager();
         Set<String> oldLocations = Sets.newLinkedHashSet(locationManager.getLocationIds());
         for (Location location: rebindContext.getLocations()) {
-            ManagementTransitionMode oldMode = locationManager.getLastManagementTransitionMode(location.getId());
-            locationManager.setManagementTransitionMode(location, RebindManagerImpl.computeMode(managementContext, location, oldMode, rebindContext.isReadOnly(location), isRebindingActiveAgain()) );
+            ManagementTransitionMode oldMode = updateTransitionMode(locationManager, location);
             if (oldMode!=null)
                 oldLocations.remove(location.getId());
         }
@@ -623,8 +624,7 @@ public abstract class RebindIteration {
         EntityManagerInternal entityManager = (EntityManagerInternal)managementContext.getEntityManager();
         Set<String> oldEntities = Sets.newLinkedHashSet(entityManager.getEntityIds());
         for (Entity entity: rebindContext.getEntities()) {
-            ManagementTransitionMode oldMode = entityManager.getLastManagementTransitionMode(entity.getId());
-            entityManager.setManagementTransitionMode(entity, RebindManagerImpl.computeMode(managementContext, entity, oldMode, rebindContext.isReadOnly(entity), isRebindingActiveAgain()) );
+            ManagementTransitionMode oldMode = updateTransitionMode(entityManager, entity);
             if (oldMode!=null)
                 oldEntities.remove(entity.getId());
         }
@@ -649,6 +649,73 @@ public abstract class RebindIteration {
         this.applications = apps;
     }
 
+    private <T extends BrooklynObject> ManagementTransitionMode updateTransitionMode(BrooklynObjectManagerInternal<T> boManager, T bo) {
+        ManagementTransitionMode oldTransitionMode = boManager.getLastManagementTransitionMode(bo.getId());
+        
+//        boManager.setManagementTransitionMode(bo, 
+//            RebindManagerImpl.computeMode(managementContext, bo, oldMode, rebindContext.isReadOnly(bo), isRebindingActiveAgain()) );
+
+//        isRebindingActiveAgain();
+        
+        ManagementTransitionMode newTransitionMode;
+        Boolean isNowReadOnly = rebindContext.isReadOnly(bo);
+        BrooklynObjectManagementMode modeBefore, modeAfter; 
+        if (oldTransitionMode==null) {
+            modeBefore = BrooklynObjectManagementMode.UNMANAGED_PERSISTED;
+//            // not previously known
+//            if (Boolean.TRUE.equals(isNowReadOnly)) {
+//                newMode = ManagementTransitionMode.REBINDING_READONLY;
+//            } else {
+//                // TODO is this needed?
+//                return ManagementTransitionMode.REBINDING_CREATING;
+//            }
+        } else {
+            modeBefore = oldTransitionMode.getModeAfter();
+        }
+
+        if (isRebindingActiveAgain()) {
+            Preconditions.checkState(!Boolean.FALSE.equals(isNowReadOnly));
+            Preconditions.checkState(modeBefore==BrooklynObjectManagementMode.MANAGED_PRIMARY);
+            modeAfter = BrooklynObjectManagementMode.MANAGED_PRIMARY;
+        } else if (isNowReadOnly) {
+            modeAfter = BrooklynObjectManagementMode.LOADED_READ_ONLY;
+        } else {
+            modeAfter = BrooklynObjectManagementMode.MANAGED_PRIMARY;
+        }
+        newTransitionMode = ManagementTransitionMode.transitioning(modeBefore, modeAfter);
+
+        boManager.setManagementTransitionMode(bo, newTransitionMode);
+
+        // XXX old logic, from RebindManagerImpl.computeMode, for reference:
+//          if (wasReadOnly==null) {
+//              // not known
+//              if (Boolean.TRUE.equals(isNowReadOnly)) return ManagementTransitionMode.REBINDING_READONLY;
+//              else {
+//                  // TODO is this needed?
+//                  return ManagementTransitionMode.REBINDING_CREATING;
+//              }
+//          } else {
+//              if (isRebindingActiveAgain) {
+//                  if (wasReadOnly || isNowReadOnly)
+//                      throw new IllegalStateException("Cannot be rebinding again to something where read-only before/after is "+wasReadOnly+"/"+isNowReadOnly);
+//                  return ManagementTransitionMode.REBINDING_ACTIVE_AGAIN;
+//              } else if (wasReadOnly && isNowReadOnly)
+//                  return ManagementTransitionMode.REBINDING_READONLY;
+//              else if (wasReadOnly)
+//                  return ManagementTransitionMode.REBINDING_BECOMING_PRIMARY;
+//              else if (isNowReadOnly)
+//                  return ManagementTransitionMode.REBINDING_NO_LONGER_PRIMARY;
+//              else {
+//                  if (isRebindingActiveAgain)
+//                  // for the most part we handle this correctly, although there may be leaks; see HighAvailabilityManagerInMemoryTest.testLocationsStillManagedCorrectlyAfterDoublePromotion
+//                  LOG.warn("Node "+(mgmt!=null ? mgmt.getManagementNodeId() : null)+" rebinding as master when already master (discouraged, may have stale references); for: "+item);
+//                  return ManagementTransitionMode.REBINDING_BECOMING_PRIMARY;
+//              }
+//          }
+        
+        return oldTransitionMode;
+    }
+
     protected abstract boolean isRebindingActiveAgain();
 
     protected Collection<String> getMementoRootEntities() {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3f7d7508/core/src/main/java/brooklyn/entity/rebind/RebindManagerImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/rebind/RebindManagerImpl.java b/core/src/main/java/brooklyn/entity/rebind/RebindManagerImpl.java
index 608f75c..9e30f7e 100644
--- a/core/src/main/java/brooklyn/entity/rebind/RebindManagerImpl.java
+++ b/core/src/main/java/brooklyn/entity/rebind/RebindManagerImpl.java
@@ -45,13 +45,11 @@ import brooklyn.entity.rebind.persister.BrooklynPersistenceUtils.CreateBackupMod
 import brooklyn.entity.rebind.persister.PersistenceActivityMetrics;
 import brooklyn.internal.BrooklynFeatureEnablement;
 import brooklyn.management.ExecutionContext;
-import brooklyn.management.ManagementContext;
 import brooklyn.management.Task;
 import brooklyn.management.ha.HighAvailabilityManagerImpl;
 import brooklyn.management.ha.ManagementNodeState;
 import brooklyn.management.ha.MementoCopyMode;
 import brooklyn.management.internal.ManagementContextInternal;
-import brooklyn.management.internal.ManagementTransitionInfo.ManagementTransitionMode;
 import brooklyn.mementos.BrooklynMementoPersister;
 import brooklyn.mementos.BrooklynMementoRawData;
 import brooklyn.mementos.TreeNode;
@@ -533,48 +531,6 @@ public class RebindManagerImpl implements RebindManager {
         return iteration.getApplications();
     }
 
-    @Deprecated /** @deprecated since 0.7.0, use method with more args */
-    static ManagementTransitionMode computeMode(ManagementContext mgmt, BrooklynObject item, ManagementTransitionMode oldMode, boolean isNowReadOnly) {
-        return computeMode(mgmt, item, oldMode==null ? null : oldMode.wasReadOnly(), isNowReadOnly, false);
-    }
-
-    @Deprecated /** @deprecated since 0.7.0, use method with more args */
-    static ManagementTransitionMode computeMode(ManagementContext mgmt, BrooklynObject item, Boolean wasReadOnly, boolean isNowReadOnly) {
-        return computeMode(mgmt, item, wasReadOnly, isNowReadOnly, false);
-    }
-
-    static ManagementTransitionMode computeMode(ManagementContext mgmt, BrooklynObject item, ManagementTransitionMode oldMode, boolean isNowReadOnly, boolean isRebindingActiveAgain) {
-        return computeMode(mgmt, item, oldMode==null ? null : oldMode.wasReadOnly(), isNowReadOnly, isRebindingActiveAgain);
-    }
-
-    static ManagementTransitionMode computeMode(ManagementContext mgmt, BrooklynObject item, Boolean wasReadOnly, boolean isNowReadOnly, boolean isRebindingActiveAgain) {
-        if (wasReadOnly==null) {
-            // not known
-            if (Boolean.TRUE.equals(isNowReadOnly)) return ManagementTransitionMode.REBINDING_READONLY;
-            else {
-                // TODO is this needed?
-                return ManagementTransitionMode.REBINDING_CREATING;
-            }
-        } else {
-            if (isRebindingActiveAgain) {
-                if (wasReadOnly || isNowReadOnly)
-                    throw new IllegalStateException("Cannot be rebinding again to something where read-only before/after is "+wasReadOnly+"/"+isNowReadOnly);
-                return ManagementTransitionMode.REBINDING_ACTIVE_AGAIN;
-            } else if (wasReadOnly && isNowReadOnly)
-                return ManagementTransitionMode.REBINDING_READONLY;
-            else if (wasReadOnly)
-                return ManagementTransitionMode.REBINDING_BECOMING_PRIMARY;
-            else if (isNowReadOnly)
-                return ManagementTransitionMode.REBINDING_NO_LONGER_PRIMARY;
-            else {
-                if (isRebindingActiveAgain)
-                // for the most part we handle this correctly, although there may be leaks; see HighAvailabilityManagerInMemoryTest.testLocationsStillManagedCorrectlyAfterDoublePromotion
-                LOG.warn("Node "+(mgmt!=null ? mgmt.getManagementNodeId() : null)+" rebinding as master when already master (discouraged, may have stale references); for: "+item);
-                return ManagementTransitionMode.REBINDING_BECOMING_PRIMARY;
-            }
-        }
-    }
-
     /**
      * Sorts the map of nodes, so that a node's parent is guaranteed to come before that node
      * (unless the parent is missing).

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3f7d7508/core/src/main/java/brooklyn/management/ha/HighAvailabilityManagerImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/management/ha/HighAvailabilityManagerImpl.java b/core/src/main/java/brooklyn/management/ha/HighAvailabilityManagerImpl.java
index dda9e19..bf8c390 100644
--- a/core/src/main/java/brooklyn/management/ha/HighAvailabilityManagerImpl.java
+++ b/core/src/main/java/brooklyn/management/ha/HighAvailabilityManagerImpl.java
@@ -58,6 +58,7 @@ import brooklyn.management.internal.LocalEntityManager;
 import brooklyn.management.internal.LocationManagerInternal;
 import brooklyn.management.internal.ManagementContextInternal;
 import brooklyn.management.internal.ManagementTransitionInfo.ManagementTransitionMode;
+import brooklyn.management.internal.ManagementTransitionInfo.BrooklynObjectManagementMode;
 import brooklyn.util.collections.MutableList;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.exceptions.Exceptions;
@@ -499,7 +500,7 @@ public class HighAvailabilityManagerImpl implements HighAvailabilityManager {
             // could perhaps promote standby items on some transitions; but for now we stop the old read-only and re-load them
             // TODO ideally there'd be an incremental rebind as well as an incremental persist
             managementContext.getRebindManager().stopReadOnly();
-            clearManagedItems(ManagementTransitionMode.REBINDING_DESTROYED);
+            clearManagedItems(ManagementTransitionMode.transitioning(BrooklynObjectManagementMode.LOADED_READ_ONLY, BrooklynObjectManagementMode.UNMANAGED_PERSISTED));
         }
     }
 
@@ -841,7 +842,10 @@ public class HighAvailabilityManagerImpl implements HighAvailabilityManager {
         }
         boolean wasMaster = (getInternalNodeState() == ManagementNodeState.MASTER);
         if (wasMaster) backupOnDemotionIfNeeded();
-        ManagementTransitionMode mode = (wasMaster ? ManagementTransitionMode.REBINDING_NO_LONGER_PRIMARY : ManagementTransitionMode.REBINDING_DESTROYED);
+        // TODO target may be RO ?
+        ManagementTransitionMode mode = ManagementTransitionMode.transitioning(
+            wasMaster ? BrooklynObjectManagementMode.MANAGED_PRIMARY : BrooklynObjectManagementMode.LOADED_READ_ONLY,
+            BrooklynObjectManagementMode.UNMANAGED_PERSISTED);
 
         nodeStateTransitionComplete = false;
         

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3f7d7508/core/src/main/java/brooklyn/management/internal/BrooklynObjectManagerInternal.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/management/internal/BrooklynObjectManagerInternal.java b/core/src/main/java/brooklyn/management/internal/BrooklynObjectManagerInternal.java
new file mode 100644
index 0000000..912e84b
--- /dev/null
+++ b/core/src/main/java/brooklyn/management/internal/BrooklynObjectManagerInternal.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package brooklyn.management.internal;
+
+import brooklyn.basic.BrooklynObject;
+import brooklyn.management.internal.ManagementTransitionInfo.ManagementTransitionMode;
+
+public interface BrooklynObjectManagerInternal<T extends BrooklynObject> {
+
+    ManagementTransitionMode getLastManagementTransitionMode(String itemId);
+    void setManagementTransitionMode(T item, ManagementTransitionMode mode);
+
+    /** 
+     * Begins management for the given rebinded root, recursively; 
+     * if rebinding as a read-only copy, {@link #setReadOnly(T, boolean)} should be called prior to this.
+     */
+    void manageRebindedRoot(T item);
+    
+    void unmanage(final T e, final ManagementTransitionMode info);
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3f7d7508/core/src/main/java/brooklyn/management/internal/EntityManagementSupport.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/management/internal/EntityManagementSupport.java b/core/src/main/java/brooklyn/management/internal/EntityManagementSupport.java
index fa5de94..4bea56e 100644
--- a/core/src/main/java/brooklyn/management/internal/EntityManagementSupport.java
+++ b/core/src/main/java/brooklyn/management/internal/EntityManagementSupport.java
@@ -296,7 +296,7 @@ public class EntityManagementSupport {
         // TODO framework stopping events - no more sensors, executions, etc
         // (elaborate or remove ^^^ ? -AH, Sept 2014)
         
-        if (!isReadOnly()) {
+        if (!isReadOnly() && info.getMode().isDestroying()) {
             // if we support remote parent of local child, the following call will need to be properly remoted
             if (entity.getParent()!=null) entity.getParent().removeChild(entity.getProxyIfAvailable());
         }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3f7d7508/core/src/main/java/brooklyn/management/internal/EntityManagerInternal.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/management/internal/EntityManagerInternal.java b/core/src/main/java/brooklyn/management/internal/EntityManagerInternal.java
index e134b23..d3a619b 100644
--- a/core/src/main/java/brooklyn/management/internal/EntityManagerInternal.java
+++ b/core/src/main/java/brooklyn/management/internal/EntityManagerInternal.java
@@ -20,26 +20,13 @@ package brooklyn.management.internal;
 
 import brooklyn.entity.Application;
 import brooklyn.entity.Entity;
-import brooklyn.location.Location;
 import brooklyn.management.EntityManager;
-import brooklyn.management.internal.ManagementTransitionInfo.ManagementTransitionMode;
 
-public interface EntityManagerInternal extends EntityManager {
+public interface EntityManagerInternal extends EntityManager, BrooklynObjectManagerInternal<Entity> {
 
     /** gets all entities currently known to the application, including entities that are not yet managed */
     Iterable<Entity> getAllEntitiesInApplication(Application application);
 
     public Iterable<String> getEntityIds();
     
-    ManagementTransitionMode getLastManagementTransitionMode(String itemId);
-    void setManagementTransitionMode(Entity item, ManagementTransitionMode mode);
-
-    /** 
-     * Begins management for the given rebinded root, recursively; 
-     * if rebinding as a read-only copy, {@link #setReadOnly(Location, boolean)} should be called prior to this.
-     */
-    void manageRebindedRoot(Entity item);
-    
-    void unmanage(final Entity e, final ManagementTransitionMode info);
-
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3f7d7508/core/src/main/java/brooklyn/management/internal/LocalEntityManager.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/management/internal/LocalEntityManager.java b/core/src/main/java/brooklyn/management/internal/LocalEntityManager.java
index 87d8a3a..aada104 100644
--- a/core/src/main/java/brooklyn/management/internal/LocalEntityManager.java
+++ b/core/src/main/java/brooklyn/management/internal/LocalEntityManager.java
@@ -55,6 +55,7 @@ import brooklyn.internal.storage.BrooklynStorage;
 import brooklyn.management.AccessController;
 import brooklyn.management.Task;
 import brooklyn.management.internal.ManagementTransitionInfo.ManagementTransitionMode;
+import brooklyn.management.internal.ManagementTransitionInfo.BrooklynObjectManagementMode;
 import brooklyn.policy.Enricher;
 import brooklyn.policy.EnricherSpec;
 import brooklyn.policy.Policy;
@@ -269,7 +270,7 @@ public class LocalEntityManager implements EntityManagerInternal {
                     new Exception("source of duplicate management of "+e));
             return;
         }
-        manageRecursive(e, ManagementTransitionMode.CREATING);
+        manageRecursive(e, ManagementTransitionMode.guessing(BrooklynObjectManagementMode.NONEXISTENT, BrooklynObjectManagementMode.MANAGED_PRIMARY));
     }
 
     @Override
@@ -306,7 +307,7 @@ public class LocalEntityManager implements EntityManagerInternal {
             }
             
             if (it.getManagementSupport().isDeployed()) {
-                if (mode==ManagementTransitionMode.CREATING) {
+                if (mode.wasNotLoaded()) {
                     // silently bail out
                     return false;
                 } else {
@@ -341,7 +342,7 @@ public class LocalEntityManager implements EntityManagerInternal {
     
     @Override
     public void unmanage(final Entity e) {
-        unmanage(e, ManagementTransitionMode.DESTROYING);
+        unmanage(e, ManagementTransitionMode.guessing(BrooklynObjectManagementMode.MANAGED_PRIMARY, BrooklynObjectManagementMode.NONEXISTENT));
     }
     
     public void unmanage(final Entity e, final ManagementTransitionMode mode) {
@@ -354,23 +355,23 @@ public class LocalEntityManager implements EntityManagerInternal {
         
         if (hasBeenReplaced) {
             // we are unmanaging an old instance after having replaced it
-            // (called from manage(...)
+            // don't unmanage or even clear its fields, because there might be references to it
             
-            if (mode==ManagementTransitionMode.REBINDING_NO_LONGER_PRIMARY) {
-                // when migrating away, these all need to be called
+            if (mode.wasReadOnly()) {
+                // if coming *from* read only; nothing needed
+            } else {
+                if (!mode.wasPrimary()) {
+                    log.warn("Unexpected mode "+mode+" for unmanage-replace "+e+" (applying anyway)");
+                }
+                // migrating away or in-place active partial rebind:
                 ((EntityInternal)e).getManagementSupport().onManagementStopping(info);
                 stopTasks(e);
                 ((EntityInternal)e).getManagementSupport().onManagementStopped(info);
-            } else {
-                // should be coming *from* read only; nothing needed
-                if (!mode.wasReadOnly()) {
-                    log.warn("Should not be unmanaging "+e+" in mode "+mode+"; ignoring");
-                }
             }
             // do not remove from maps below, bail out now
             return;
             
-        } else if (mode==ManagementTransitionMode.REBINDING_DESTROYED) {
+        } else if (mode.wasReadOnly() && mode.isDestroying()) {
             // we are unmanaging an instance (secondary) for which the primary has been destroyed elsewhere
             ((EntityInternal)e).getManagementSupport().onManagementStopping(info);
             unmanageNonRecursive(e);
@@ -379,7 +380,7 @@ public class LocalEntityManager implements EntityManagerInternal {
             managementContext.getRebindManager().getChangeListener().onUnmanaged(e);
             if (managementContext.getGarbageCollector() != null) managementContext.getGarbageCollector().onUnmanaged(e);
             
-        } else if (mode==ManagementTransitionMode.DESTROYING) {
+        } else if (mode.wasPrimary() && mode.isDestroying()) {
             // we are unmanaging an instance either because it is being destroyed (primary), 
             // or due to an explicit call (shutting down all things, read-only and primary);
             // in either case, should be recursive
@@ -545,11 +546,11 @@ public class LocalEntityManager implements EntityManagerInternal {
         Object old = preManagedEntitiesById.put(e.getId(), realE);
         preRegisteredEntitiesById.remove(e.getId());
         
-        if (old!=null && mode==ManagementTransitionMode.CREATING) {
+        if (old!=null && mode.wasNotLoaded()) {
             if (old.equals(e)) {
-                log.warn("{} redundant call to pre-start management of entity {}; ignoring", this, e);
+                log.warn("{} redundant call to pre-start management of entity {}, mode {}; ignoring", new Object[] { this, e, mode });
             } else {
-                throw new IllegalStateException("call to pre-manage entity "+e+" but different entity "+old+" already known under that id at "+this);
+                throw new IllegalStateException("call to pre-manage entity "+e+" ("+mode+") but different entity "+old+" already known under that id at "+this);
             }
             return false;
         } else {
@@ -567,11 +568,11 @@ public class LocalEntityManager implements EntityManagerInternal {
     private synchronized boolean manageNonRecursive(Entity e, ManagementTransitionMode mode) {
         Entity old = entitiesById.get(e.getId());
         
-        if (old!=null && mode==ManagementTransitionMode.CREATING) {
+        if (old!=null && mode.wasNotLoaded()) {
             if (old.equals(e)) {
                 log.warn("{} redundant call to start management of entity {}; ignoring", this, e);
             } else {
-                throw new IllegalStateException("call to manage entity "+e+" but different entity "+old+" already known under that id at "+this);
+                throw new IllegalStateException("call to manage entity "+e+" ("+mode+") but different entity "+old+" already known under that id at "+this);
             }
             return false;
         }
@@ -583,8 +584,8 @@ public class LocalEntityManager implements EntityManagerInternal {
         Entity oldProxy = entityProxiesById.get(e.getId());
         Entity proxyE;
         if (oldProxy!=null) {
-            if (mode==ManagementTransitionMode.CREATING) {
-                throw new IllegalStateException("call to manage entity "+e+" but already had proxy "+oldProxy+" already known under that id at "+this);
+            if (mode.wasNotLoaded()) {
+                throw new IllegalStateException("call to manage entity "+e+" from unloaded state ("+mode+") but already had proxy "+oldProxy+" already known under that id at "+this);
             }
             // make the old proxy point at this new delegate
             // (some other tricks done in the call below)

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3f7d7508/core/src/main/java/brooklyn/management/internal/LocalLocationManager.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/management/internal/LocalLocationManager.java b/core/src/main/java/brooklyn/management/internal/LocalLocationManager.java
index b873363..fec09f4 100644
--- a/core/src/main/java/brooklyn/management/internal/LocalLocationManager.java
+++ b/core/src/main/java/brooklyn/management/internal/LocalLocationManager.java
@@ -43,6 +43,7 @@ import brooklyn.location.basic.LocationInternal;
 import brooklyn.management.AccessController;
 import brooklyn.management.entitlement.Entitlements;
 import brooklyn.management.internal.ManagementTransitionInfo.ManagementTransitionMode;
+import brooklyn.management.internal.ManagementTransitionInfo.BrooklynObjectManagementMode;
 import brooklyn.util.config.ConfigBag;
 import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.exceptions.RuntimeInterruptedException;
@@ -194,7 +195,7 @@ public class LocalLocationManager implements LocationManagerInternal {
             log.warn("Parent location "+parent+" of "+loc+" is not managed; attempting to manage it (in future this may be disallowed)");
             return manage(parent);
         } else {
-            return manageRecursive(loc, ManagementTransitionMode.CREATING);
+            return manageRecursive(loc, ManagementTransitionMode.guessing(BrooklynObjectManagementMode.NONEXISTENT, BrooklynObjectManagementMode.MANAGED_PRIMARY));
         }
     }
     
@@ -214,7 +215,7 @@ public class LocalLocationManager implements LocationManagerInternal {
         long count = LOCATION_CNT.incrementAndGet();
         if (log.isDebugEnabled()) {
             String msg = "Managing location " + loc + " ("+initialMode+"), from " + Tasks.current()+" / "+Entitlements.getEntitlementContext();
-            LoggingLevel level = (initialMode==ManagementTransitionMode.REBINDING_READONLY ? LoggingLevel.TRACE : LoggingLevel.DEBUG);
+            LoggingLevel level = (!initialMode.wasNotLoaded() || initialMode.isReadOnly() ? LoggingLevel.TRACE : LoggingLevel.DEBUG);
             if (count % 100 == 0) {
                 // include trace periodically in case we get leaks or too much location management
                 BrooklynLogging.log(log, level,
@@ -231,7 +232,7 @@ public class LocalLocationManager implements LocationManagerInternal {
             }
             
             if (it.isManaged()) {
-                if (mode==ManagementTransitionMode.CREATING) {
+                if (mode.wasNotLoaded()) {
                     // silently bail out
                     return false;
                 } else {
@@ -242,9 +243,9 @@ public class LocalLocationManager implements LocationManagerInternal {
             boolean result = manageNonRecursive(it, mode);
             if (result) {
                 it.setManagementContext(managementContext);
-                if (!mode.isReadOnly()) {
+                if (mode.isPrimary()) {
                     it.onManagementStarted();
-                    if (!mode.wasReadOnly() && !mode.isRebinding()) {
+                    if (mode.isCreating()) {
                         // Never record event on rebind; this isn't the location (e.g. the VM) being "created"
                         // so don't tell listeners that.
                         // TODO The location-event history should be persisted; currently it is lost on
@@ -261,7 +262,7 @@ public class LocalLocationManager implements LocationManagerInternal {
     
     @Override
     public void unmanage(final Location loc) {
-        unmanage(loc, ManagementTransitionMode.DESTROYING);
+        unmanage(loc, ManagementTransitionMode.guessing(BrooklynObjectManagementMode.MANAGED_PRIMARY, BrooklynObjectManagementMode.NONEXISTENT));
     }
     
     public void unmanage(final Location loc, final ManagementTransitionMode mode) {
@@ -274,26 +275,34 @@ public class LocalLocationManager implements LocationManagerInternal {
         if (hasBeenReplaced) {
             // we are unmanaging an old instance after having replaced it; 
             // don't unmanage or even clear its fields, because there might be references to it
-            if (mode==ManagementTransitionMode.REBINDING_NO_LONGER_PRIMARY) {
-                // when migrating away, these all need to be called
+            
+            if (mode.wasReadOnly()) {
+                // if coming *from* read only; nothing needed
+            } else {
+                if (!mode.wasPrimary()) {
+                    log.warn("Unexpected mode "+mode+" for unmanage-replace "+loc+" (applying anyway)");
+                }
+                // migrating away or in-place active partial rebind:
                 managementContext.getRebindManager().getChangeListener().onUnmanaged(loc);
                 if (managementContext.gc != null) managementContext.gc.onUnmanaged(loc);
-            } else {
-                // should be coming *from* read only; nothing needed
-                if (!mode.wasReadOnly())
-                    log.warn("Should not be unmanaging "+loc+" in mode "+mode+"; ignoring");
             }
             // do not remove from maps below, bail out now
             return;
 
-        } else if (mode==ManagementTransitionMode.REBINDING_DESTROYED || mode==ManagementTransitionMode.REBINDING_NO_LONGER_PRIMARY) {
+        } else if ((mode.isReadOnly() && mode.wasPrimary()) || (mode.isDestroying() && mode.wasReadOnly())) {
+            if (mode.isReadOnly() && mode.wasPrimary()) {
+                // TODO shouldn't this fall into "hasBeenReplaced" above?
+                log.debug("Unmanaging on demotion: "+loc+" ("+mode+")");
+            }
             // we are unmanaging an instance whose primary management is elsewhere (either we were secondary, or we are being demoted)
             unmanageNonRecursiveRemoveFromRecords(loc, mode);
             managementContext.getRebindManager().getChangeListener().onUnmanaged(loc);
             if (managementContext.gc != null) managementContext.gc.onUnmanaged(loc);
             unmanageNonRecursiveClearItsFields(loc, mode);
+        } else if (mode.isDestroying()) {
+
+            // TODO isUnloading???
             
-        } else if (mode==ManagementTransitionMode.DESTROYING) {
             // we are unmanaging an instance either because it is being destroyed (primary), 
             // or due to an explicit call (shutting down all things, read-only and primary);
             // in either case, should be recursive
@@ -307,11 +316,11 @@ public class LocalLocationManager implements LocationManagerInternal {
                     if (mode==null) {
                         // ad hoc creation e.g. tests
                         log.debug("Missing transition mode for "+it+" when unmanaging; assuming primary/destroying");
-                        mode = ManagementTransitionMode.DESTROYING;
+                        mode = ManagementTransitionMode.guessing(BrooklynObjectManagementMode.MANAGED_PRIMARY, BrooklynObjectManagementMode.NONEXISTENT);
                     }
-                    if (!mode.isReadOnly()) it.onManagementStopped();
+                    if (mode.wasPrimary()) it.onManagementStopped();
                     managementContext.getRebindManager().getChangeListener().onUnmanaged(it);
-                    if (!mode.isReadOnly()) recordLocationEvent(it, Lifecycle.DESTROYED);
+                    if (mode.isDestroying()) recordLocationEvent(it, Lifecycle.DESTROYED);
                     if (managementContext.gc != null) managementContext.gc.onUnmanaged(it);
                 }
                 unmanageNonRecursiveClearItsFields(loc, mode);
@@ -319,6 +328,8 @@ public class LocalLocationManager implements LocationManagerInternal {
             } });
             
         } else {
+            // what about to unmanaged_persisted?
+            
             log.warn("Invalid mode for unmanage: "+mode+" on "+loc+" (ignoring)");
         }
         
@@ -367,7 +378,7 @@ public class LocalLocationManager implements LocationManagerInternal {
 
         locationTypes.put(loc.getId(), loc.getClass().getName());
         
-        if (old!=null && mode==ManagementTransitionMode.CREATING) {
+        if (old!=null && mode.wasNotLoaded()) {
             if (old.equals(loc)) {
                 log.warn("{} redundant call to start management of location {}", this, loc);
             } else {
@@ -386,7 +397,7 @@ public class LocalLocationManager implements LocationManagerInternal {
 
     @SuppressWarnings({ "rawtypes", "unchecked" })
     private synchronized void unmanageNonRecursiveClearItsFields(Location loc, ManagementTransitionMode mode) {
-        if (mode==ManagementTransitionMode.DESTROYING) {
+        if (mode.isDestroying()) {
             ((AbstractLocation)loc).setParent(null, true);
             
             Location parent = ((AbstractLocation)loc).getParent();

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3f7d7508/core/src/main/java/brooklyn/management/internal/LocationManagerInternal.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/management/internal/LocationManagerInternal.java b/core/src/main/java/brooklyn/management/internal/LocationManagerInternal.java
index 96e2ff3..4b0d959 100644
--- a/core/src/main/java/brooklyn/management/internal/LocationManagerInternal.java
+++ b/core/src/main/java/brooklyn/management/internal/LocationManagerInternal.java
@@ -20,21 +20,9 @@ package brooklyn.management.internal;
 
 import brooklyn.location.Location;
 import brooklyn.management.LocationManager;
-import brooklyn.management.internal.ManagementTransitionInfo.ManagementTransitionMode;
 
-public interface LocationManagerInternal extends LocationManager {
+public interface LocationManagerInternal extends LocationManager, BrooklynObjectManagerInternal<Location> {
 
     public Iterable<String> getLocationIds();
 
-    ManagementTransitionMode getLastManagementTransitionMode(String itemId);
-    void setManagementTransitionMode(Location item, ManagementTransitionMode mode);
-
-    /** 
-     * Begins management for the given rebinded root, recursively; 
-     * if rebinding as a read-only copy, {@link #setReadOnly(Location, boolean)} should be called prior to this.
-     */
-    void manageRebindedRoot(Location item);
-
-    void unmanage(final Location item, final ManagementTransitionMode info);
-
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3f7d7508/core/src/main/java/brooklyn/management/internal/ManagementTransitionInfo.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/management/internal/ManagementTransitionInfo.java b/core/src/main/java/brooklyn/management/internal/ManagementTransitionInfo.java
index 6d27fed..6ce714a 100644
--- a/core/src/main/java/brooklyn/management/internal/ManagementTransitionInfo.java
+++ b/core/src/main/java/brooklyn/management/internal/ManagementTransitionInfo.java
@@ -20,46 +20,119 @@ package brooklyn.management.internal;
 
 import brooklyn.management.ManagementContext;
 
+import com.google.common.base.Preconditions;
+
 public class ManagementTransitionInfo {
 
     final ManagementContext mgmtContext;
-    
     final ManagementTransitionMode mode;
     
-    /** true if this transition is an entity whose mastering is migrating from one node to another;
-     * false if the brooklyn mgmt plane is just starting managing of this entity for the very first time  
-     */
+    public enum BrooklynObjectManagementMode {
+        /** item does not exist, not in memory, nor persisted (e.g. creating for first time, or finally destroying) */
+        NONEXISTENT, 
+        /** item exists or existed elsewhere, i.e. there is persisted state, but is not loaded here */
+        UNMANAGED_PERSISTED, 
+        
+        @Deprecated /** @deprecated marking places where we aren't sure */
+        /** either nonexistent or persisted by unmanaged */
+        ITEM_UNKNOWN, 
+        
+        /** item is loaded but read-only (ie not actively managed here) */
+        LOADED_READ_ONLY, 
+        /** item is actively managed here */
+        MANAGED_PRIMARY 
+    }
+    
+    public static class ManagementTransitionMode {
 
-    public enum ManagementTransitionMode {
-        /** Item is being created fresh, for the first time */ 
-        CREATING(false, false, false),
-        /** Item is being destroyed / stopping permanently */ 
-        DESTROYING(false, false, false),
+        // XXX
+//-        CREATING(false, false, false),
+//-        DESTROYING(false, false, false),
+//-        REBINDING_READONLY(true, true, true),
+//-        REBINDING_NO_LONGER_PRIMARY(false, true, true), 
+//-        REBINDING_BECOMING_PRIMARY(true, false, true),
+//-        REBINDING_DESTROYED(true, true, true),
+//-        REBINDING_CREATING(false, false, true);
+//-        
+//-        private final boolean wasReadOnly;
+//-        private final boolean isReadOnly;
+//-        private final boolean isRebinding;
+
+//        /** Item is being created fresh, for the first time */ 
+//        CREATING(NONEXISTENT, MANAGED_PRIMARY),
+//        /** Item is being destroyed / stopping permanently */ 
+//        DESTROYING(MANAGED_PRIMARY, NONEXISTENT),
+//        
+//        /** Item is being mirrored (refreshed or created) here from a serialized/specified state */
+//        REBINDING_READONLY(LOADED_READ_ONLY, LOADED_READ_ONLY),
+//        /** Item management is stopping here, going elsewhere */
+//        REBINDING_NO_LONGER_PRIMARY(MANAGED_PRIMARY, LOADED_READ_ONLY), 
+//        /** Item management is starting here, having previously been running elsewhere */
+//        REBINDING_BECOMING_PRIMARY(LOADED_READ_ONLY, MANAGED_PRIMARY),
+//        /** Item has been managed here, and is being re-read for management again (e.g. applying a transform) */
+//        REBINDING_ACTIVE_AGAIN(MANAGED_PRIMARY, MANAGED_PRIMARY),
+//        /** Item was being mirrored but has now been destroyed  */
+//        REBINDING_DESTROYED(LOADED_READ_ONLY, NONEXISTENT),
+//
+//        /** Item management is starting here, from persisted state */
+//        REBINDING_CREATING(NodeManagementMode.UNMANAGED_PERSISTED, NodeManagementMode.MANAGED_PRIMARY);
         
-        /** Item is being mirrored (or refreshed) here from a serialized/specified state */
-        REBINDING_READONLY(true, true, true),
-        /** Item management is stopping here, going elsewhere */
-        REBINDING_NO_LONGER_PRIMARY(false, true, true), 
-        /** Item management is starting here, having previously been running elsewhere */
-        REBINDING_BECOMING_PRIMARY(true, false, true),
-        /** Item was being mirrored but has now been destroyed  */
-        REBINDING_DESTROYED(true, true, true),
-        /** Item management is starting here, where not sure what previous running state was */
-        REBINDING_CREATING(false, false, true);
+//        private final static ManagementTransitionTargetMode NONE = ManagementTransitionTargetMode.NONE;
+        private final BrooklynObjectManagementMode modeBefore, modeAfter;
+
+        private ManagementTransitionMode(BrooklynObjectManagementMode modeBefore, BrooklynObjectManagementMode modeAfter) {
+            this.modeBefore = modeBefore;
+            this.modeAfter = modeAfter;
+        }
         
-        private final boolean wasReadOnly;
-        private final boolean isReadOnly;
-        private final boolean isRebinding;
+        public static ManagementTransitionMode transitioning(BrooklynObjectManagementMode modeBefore, BrooklynObjectManagementMode modeAfter) {
+            return new ManagementTransitionMode(Preconditions.checkNotNull(modeBefore, "modeBefore"), Preconditions.checkNotNull(modeAfter, "modeAfter"));
+        }
+
+        @Deprecated /** @deprecated marking places where we aren't sure */
+        public static ManagementTransitionMode guessing(BrooklynObjectManagementMode modeBefore, BrooklynObjectManagementMode modeAfter) {
+            return transitioning(modeBefore, modeAfter);
+        }
+
+        public BrooklynObjectManagementMode getModeBefore() {
+            return modeBefore;
+        }
         
-        ManagementTransitionMode(boolean wasReadOnly, boolean isReadOnly, boolean isRebinding) {
-            this.wasReadOnly = wasReadOnly;
-            this.isReadOnly = isReadOnly;
-            this.isRebinding = isRebinding;
+        public BrooklynObjectManagementMode getModeAfter() {
+            return modeAfter;
         }
         
-        public boolean wasReadOnly() { return wasReadOnly; }
-        public boolean isReadOnly() { return isReadOnly; }
-        public boolean isRebinding() { return isRebinding; }
+        public boolean wasNotLoaded() {
+            return getModeBefore()==BrooklynObjectManagementMode.NONEXISTENT || getModeBefore()==BrooklynObjectManagementMode.UNMANAGED_PERSISTED || getModeBefore()==BrooklynObjectManagementMode.ITEM_UNKNOWN;
+        }
+
+        public boolean isNoLongerLoaded() {
+            return getModeAfter()==BrooklynObjectManagementMode.NONEXISTENT || getModeAfter()==BrooklynObjectManagementMode.UNMANAGED_PERSISTED || getModeAfter()==BrooklynObjectManagementMode.ITEM_UNKNOWN;
+        }
+
+        public boolean wasPrimary() {
+            return getModeBefore()==BrooklynObjectManagementMode.MANAGED_PRIMARY;
+        }
+        
+        public boolean isPrimary() {
+            return getModeAfter()==BrooklynObjectManagementMode.MANAGED_PRIMARY;
+        }
+
+        public boolean wasReadOnly() {
+            return getModeBefore()==BrooklynObjectManagementMode.LOADED_READ_ONLY;
+        }
+        
+        public boolean isReadOnly() {
+            return getModeAfter()==BrooklynObjectManagementMode.LOADED_READ_ONLY;
+        }
+
+        public boolean isDestroying() {
+            return getModeAfter()==BrooklynObjectManagementMode.NONEXISTENT;
+        }
+
+        public boolean isCreating() {
+            return getModeBefore()==BrooklynObjectManagementMode.NONEXISTENT;
+        }
     }
     
     public ManagementTransitionInfo(ManagementContext mgmtContext, ManagementTransitionMode mode) {