/* * 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 org.apache.brooklyn.core.mgmt.rebind; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.concurrent.Semaphore; import java.util.concurrent.atomic.AtomicInteger; import org.apache.brooklyn.api.entity.Entity; import org.apache.brooklyn.api.mgmt.ha.ManagementNodeState; import org.apache.brooklyn.api.mgmt.rebind.RebindExceptionHandler; import org.apache.brooklyn.api.mgmt.rebind.mementos.BrooklynMementoPersister; import org.apache.brooklyn.api.mgmt.rebind.mementos.BrooklynMementoRawData; import org.apache.brooklyn.api.mgmt.rebind.mementos.Memento; import org.apache.brooklyn.api.mgmt.rebind.mementos.BrooklynMementoRawData.Builder; import org.apache.brooklyn.api.objs.BrooklynObject; import org.apache.brooklyn.api.objs.BrooklynObjectType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.apache.brooklyn.core.entity.EntityInternal; import org.apache.brooklyn.core.mgmt.persist.BrooklynMementoPersisterToObjectStore; import org.apache.brooklyn.core.mgmt.persist.PersistenceActivityMetrics; import org.apache.brooklyn.core.mgmt.rebind.transformer.CompoundTransformer; import org.apache.brooklyn.core.objs.BrooklynObjectInternal; import org.apache.brooklyn.util.collections.MutableList; import org.apache.brooklyn.util.collections.MutableSet; import com.google.common.base.Preconditions; /** * Replaces a set of existing entities (and their adjunts) and locations: * writes their state, applies a transformation, then reads the state back. */ public class ActivePartialRebindIteration extends RebindIteration { private static final Logger LOG = LoggerFactory.getLogger(ActivePartialRebindIteration.class); protected Iterator<BrooklynObject> objectsToRebindInitial; protected Collection<BrooklynObject> objectsToRebindFinal; protected List<CompoundTransformer> transformers = MutableList.of(); public ActivePartialRebindIteration(RebindManagerImpl rebindManager, ManagementNodeState mode, ClassLoader classLoader, RebindExceptionHandler exceptionHandler, Semaphore rebindActive, AtomicInteger readOnlyRebindCount, PersistenceActivityMetrics rebindMetrics, BrooklynMementoPersister persistenceStoreAccess ) { super(rebindManager, mode, classLoader, exceptionHandler, rebindActive, readOnlyRebindCount, rebindMetrics, persistenceStoreAccess); } @Override protected boolean isRebindingActiveAgain() { return true; } public void setObjectIterator(Iterator<BrooklynObject> objectsToRebind) { this.objectsToRebindInitial = objectsToRebind; } public void applyTransformer(CompoundTransformer transformer) { transformers.add(Preconditions.checkNotNull(transformer, "transformer")); } @Override protected void doRun() throws Exception { Preconditions.checkState(rebindManager.getRebindMode()==ManagementNodeState.MASTER, "Partial rebind only supported in master mode, not "+rebindManager.getRebindMode()); Preconditions.checkState(readOnlyRebindCount.get()==Integer.MIN_VALUE, "Rebind count should be MIN when running in master mode"); Preconditions.checkNotNull(objectsToRebindInitial, "Objects to rebind must be set"); LOG.debug("Partial rebind Rebinding ("+mode+") from "+rebindManager.getPersister().getBackingStoreDescription()+"..."); super.doRun(); } /** Rather than loading from the remote persistence store (as {@link InitialFullRebindIteration} does), * this constructs the memento data by serializing the objects we are replacing. * TODO: Currently this does not do any pausing or unmanagement or guarding write access, * so there is a short window for data loss between this write and the subsequent read. */ @Override protected void loadManifestFiles() throws Exception { checkEnteringPhase(1); Builder mementoRawBuilder = BrooklynMementoRawData.builder(); /* * Unmanagement is done as part of the "manage" call, entity by entity. */ objectsToRebindFinal = MutableSet.of(); while (objectsToRebindInitial.hasNext()) { BrooklynObject bo = objectsToRebindInitial.next(); objectsToRebindFinal.add(bo); if (bo instanceof Entity) { // if it's an entity, add all adjuncts. (if doing some sort of pause, that's maybe not necessary...) objectsToRebindFinal.addAll( ((EntityInternal)bo).getPolicies() ); objectsToRebindFinal.addAll( ((EntityInternal)bo).getEnrichers() ); objectsToRebindFinal.addAll( ((EntityInternal)bo).feeds().getFeeds() ); } } // get serialization for (BrooklynObject bo: objectsToRebindFinal) { Memento m = ((BrooklynObjectInternal)bo).getRebindSupport().getMemento(); BrooklynMementoPersister p = rebindManager.getPersister(); String mr = ((BrooklynMementoPersisterToObjectStore)p).getMementoSerializer().toString(m); mementoRawBuilder.put(BrooklynObjectType.of(bo), bo.getId(), mr); } // then rebuild mementoRawData = mementoRawBuilder.build(); preprocessManifestFiles(); } @Override protected void preprocessManifestFiles() throws Exception { for (CompoundTransformer transformer: transformers) { mementoRawData = transformer.transform(mementoRawData); } super.preprocessManifestFiles(); overwritingMaster = true; } @Override protected void rebuildCatalog() { checkEnteringPhase(2); // skip; old catalog items should be re-used } @Override protected Collection<String> getMementoRootEntities() { // all entities are roots here, because we are not recursing return memento.getEntityIds(); } @Override protected void cleanupOldLocations(Set<String> oldLocations) { // not applicable here } @Override protected void cleanupOldEntities(Set<String> oldEntities) { // not applicable here } }