keep a cache of osgi bundles brooklyn installs, incl 1 bak, and rollback on failure
removes other no-longer-needed temp file the cache is a temp dir and deleted on brooklyn server close (since we can reload from rebind) Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/e8e39fd7 Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/e8e39fd7 Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/e8e39fd7 Branch: refs/heads/master Commit: e8e39fd7ef55c833f2b4a735ee591667242e0ab1 Parents: 8127dbb Author: Alex Heneveld <[email protected]> Authored: Wed Aug 16 16:40:03 2017 +0100 Committer: Alex Heneveld <[email protected]> Committed: Thu Aug 17 10:31:23 2017 +0100 ---------------------------------------------------------------------- .../CatalogOsgiVersionMoreEntityRebindTest.java | 17 +-- .../catalog/internal/BasicBrooklynCatalog.java | 17 +-- .../catalog/internal/CatalogBundleLoader.java | 17 --- .../core/mgmt/ha/OsgiArchiveInstaller.java | 42 +++++-- .../brooklyn/core/mgmt/ha/OsgiManager.java | 125 +++++++++++++------ .../BrooklynMementoPersisterToObjectStore.java | 20 +-- .../core/typereg/BasicManagedBundle.java | 23 ++-- 7 files changed, 155 insertions(+), 106 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e8e39fd7/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiVersionMoreEntityRebindTest.java ---------------------------------------------------------------------- diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiVersionMoreEntityRebindTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiVersionMoreEntityRebindTest.java index 0bea66c..cb2d2cb 100644 --- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiVersionMoreEntityRebindTest.java +++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiVersionMoreEntityRebindTest.java @@ -408,12 +408,13 @@ public class CatalogOsgiVersionMoreEntityRebindTest extends AbstractYamlRebindTe } } - @Test(groups="Broken") // AH think not going to support this; see notes in BasicBrooklynCatalog.scanAnnotationsInBundle - // it's hard to get the JAR for scanning, and doesn't fit with the OSGi way - public void testRebindJavaScanningBundleInCatalog() throws Exception { - CatalogScanOsgiTest.installJavaScanningMoreEntitiesV2(mgmt(), this); - rebind(); - RegisteredType item = mgmt().getTypeRegistry().get(OsgiTestResources.BROOKLYN_TEST_MORE_ENTITIES_MORE_ENTITY); - Assert.assertNotNull(item, "Scanned item should have been available after rebind"); - } + // could support this now that we have a local cache; but probably not needed; see BasicBrooklynCatalog.scanAnnotationsInBundle +// @Test +// public void testRebindJavaScanningBundleInCatalog() throws Exception { +// CatalogScanOsgiTest.installJavaScanningMoreEntitiesV2(mgmt(), this); +// rebind(); +// RegisteredType item = mgmt().getTypeRegistry().get(OsgiTestResources.BROOKLYN_TEST_MORE_ENTITIES_MORE_ENTITY); +// Assert.assertNotNull(item, "Scanned item should have been available after rebind"); +// } + } http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e8e39fd7/core/src/main/java/org/apache/brooklyn/core/catalog/internal/BasicBrooklynCatalog.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/BasicBrooklynCatalog.java b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/BasicBrooklynCatalog.java index deaae6f..87725dd 100644 --- a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/BasicBrooklynCatalog.java +++ b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/BasicBrooklynCatalog.java @@ -61,7 +61,6 @@ import org.apache.brooklyn.core.mgmt.ha.OsgiManager; import org.apache.brooklyn.core.mgmt.internal.CampYamlParser; import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal; import org.apache.brooklyn.core.typereg.BasicBrooklynTypeRegistry; -import org.apache.brooklyn.core.typereg.BasicManagedBundle; import org.apache.brooklyn.core.typereg.BasicRegisteredType; import org.apache.brooklyn.core.typereg.BasicTypeImplementationPlan; import org.apache.brooklyn.core.typereg.BrooklynTypePlanTransformer; @@ -112,7 +111,7 @@ import com.google.common.collect.Iterables; import com.google.common.collect.Maps; /* TODO the complex tree-structured catalogs are only useful when we are relying on those separate catalog classloaders - * to isolate classpaths. with osgi everything is just put into the "manual additions" catalog. */ + * to isolate classpaths. with osgi everything is just put into the "manual additions" catalog. Deprecate/remove this. */ public class BasicBrooklynCatalog implements BrooklynCatalog { public static final String POLICIES_KEY = "brooklyn.policies"; public static final String ENRICHERS_KEY = "brooklyn.enrichers"; @@ -1058,25 +1057,21 @@ public class BasicBrooklynCatalog implements BrooklynCatalog { } @SuppressWarnings("unused") // keep during 0.12.0 until we are decided we won't support this; search for this method name - // note that it breaks after rebind since we don't have the JAR -- see notes below + // (note that this now could work after rebind since we have the OSGi cache) private Collection<CatalogItemDtoAbstract<?, ?>> scanAnnotationsInBundle(ManagementContext mgmt, ManagedBundle containingBundle) { CatalogDto dto = CatalogDto.newNamedInstance("Bundle "+containingBundle.getVersionedName().toOsgiString()+" Scanned Catalog", "All annotated Brooklyn entities detected in bundles", "scanning-bundle-"+containingBundle.getVersionedName().toOsgiString()); CatalogDo subCatalog = new CatalogDo(dto); // need access to a JAR to scan this String url = null; - if (containingBundle instanceof BasicManagedBundle) { - File f = ((BasicManagedBundle)containingBundle).getTempLocalFileWhenJustUploaded(); - if (f!=null) { - url = "file:"+f.getAbsolutePath(); - } + File f = ((ManagementContextInternal)mgmt).getOsgiManager().get().getBundleFile(containingBundle); + if (f!=null) { + url = "file:"+f.getAbsolutePath(); } - // type.getSubPathName(), type, id+".jar", com.google.common.io.Files.asByteSource(f), exceptionHandler); if (url==null) { url = containingBundle.getUrl(); } if (url==null) { - // NOT available after persistence/rebind - // as shown by test in CatalogOsgiVersionMoreEntityRebindTest + // should now always be available throw new IllegalArgumentException("Error preparing to scan "+containingBundle.getVersionedName()+": no URL available"); } // org.reflections requires the URL to be "file:" containg ".jar" http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e8e39fd7/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogBundleLoader.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogBundleLoader.java b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogBundleLoader.java index df2f212..f690df0 100644 --- a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogBundleLoader.java +++ b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogBundleLoader.java @@ -19,13 +19,10 @@ package org.apache.brooklyn.core.catalog.internal; -import static org.apache.brooklyn.api.catalog.CatalogItem.CatalogItemType.TEMPLATE; - import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.util.Collection; -import java.util.List; import java.util.Map; import java.util.Set; @@ -157,18 +154,4 @@ public class CatalogBundleLoader { } } - private Iterable<? extends CatalogItem<?, ?>> removeApplications(Iterable<? extends CatalogItem<?, ?>> catalogItems) { - - List<CatalogItem<?, ?>> result = MutableList.of(); - - for (CatalogItem<?, ?> item : catalogItems) { - if (TEMPLATE.equals(item.getCatalogItemType())) { - removeFromCatalog(item); - } else { - result.add(item); - } - } - return result; - } - } http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e8e39fd7/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/OsgiArchiveInstaller.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/OsgiArchiveInstaller.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/OsgiArchiveInstaller.java index 0b018b2..d294ad5 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/OsgiArchiveInstaller.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/OsgiArchiveInstaller.java @@ -39,6 +39,7 @@ import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal; import org.apache.brooklyn.core.typereg.BasicBrooklynTypeRegistry; import org.apache.brooklyn.core.typereg.BasicManagedBundle; import org.apache.brooklyn.core.typereg.RegisteredTypePredicates; +import org.apache.brooklyn.core.typereg.RegisteredTypes; import org.apache.brooklyn.util.collections.MutableList; import org.apache.brooklyn.util.collections.MutableMap; import org.apache.brooklyn.util.core.ResourceUtils; @@ -354,21 +355,26 @@ class OsgiArchiveInstaller { } osgiManager.checkCorrectlyInstalled(result.getMetadata(), result.bundle); - File oldZipIfSet = ((BasicManagedBundle)result.getMetadata()).getTempLocalFileWhenJustUploaded(); - ((BasicManagedBundle)result.getMetadata()).setTempLocalFileWhenJustUploaded(zipFile); - zipFile = null; // don't close/delete it here, we'll use it for uploading, then it will delete it + final File oldZipFile; if (!updating) { - osgiManager.managedBundlesRecord.addManagedBundle(result); + oldZipFile = null; + osgiManager.managedBundlesRecord.addManagedBundle(result, zipFile); result.code = OsgiBundleInstallationResult.ResultCode.INSTALLED_NEW_BUNDLE; result.message = "Installed Brooklyn catalog bundle "+result.getMetadata().getVersionedName()+" with ID "+result.getMetadata().getId()+" ["+result.bundle.getBundleId()+"]"; + ((BasicManagedBundle)result.getMetadata()).setPersistenceNeeded(true); mgmt().getRebindManager().getChangeListener().onManaged(result.getMetadata()); } else { + oldZipFile = osgiManager.managedBundlesRecord.updateManagedBundleFile(result, zipFile); result.code = OsgiBundleInstallationResult.ResultCode.UPDATED_EXISTING_BUNDLE; result.message = "Updated Brooklyn catalog bundle "+result.getMetadata().getVersionedName()+" as existing ID "+result.getMetadata().getId()+" ["+result.bundle.getBundleId()+"]"; + ((BasicManagedBundle)result.getMetadata()).setPersistenceNeeded(true); mgmt().getRebindManager().getChangeListener().onChanged(result.getMetadata()); } log.debug(result.message + " (in osgi container)"); + // can now delete and close (copy has been made and is available from OsgiManager) + zipFile.delete(); + zipFile = null; // setting the above before the code below means if there is a problem starting or loading catalog items // a user has to remove then add again, or forcibly reinstall; @@ -384,22 +390,26 @@ class OsgiArchiveInstaller { Runnable startRunnable = new Runnable() { private void rollbackBundle() { if (updating) { - if (oldZipIfSet!=null) { - ((BasicManagedBundle)result.getMetadata()).setTempLocalFileWhenJustUploaded(oldZipIfSet); - } else { - // TODO look in persistence + if (oldZipFile==null) { + throw new IllegalStateException("Did not have old ZIP file to install"); } - log.debug("Rolling back bundle "+result.getVersionedName()+" to state from "+oldZipIfSet); + log.debug("Rolling back bundle "+result.getVersionedName()+" to state from "+oldZipFile); + osgiManager.managedBundlesRecord.updateManagedBundleFile(result, oldZipFile); try { - result.bundle.update(new FileInputStream(Preconditions.checkNotNull(oldZipIfSet, "Couldn't find contents of old version of bundle"))); + result.bundle.update(new FileInputStream(Preconditions.checkNotNull(oldZipFile, "Couldn't find contents of old version of bundle"))); } catch (Exception e) { log.error("Error rolling back following failed install of updated "+result.getVersionedName()+"; " + "installation will likely be corrupted and correct version should be manually installed.", e); } + ((BasicManagedBundle)result.getMetadata()).setPersistenceNeeded(true); + mgmt().getRebindManager().getChangeListener().onChanged(result.getMetadata()); } else { - log.debug("Uninstalling bundle "+result.getVersionedName()+" (rolling back, but no previous version)"); + log.debug("Uninstalling bundle "+result.getVersionedName()+" (roll back of failed fresh install, no previous version to revert to)"); osgiManager.uninstallUploadedBundle(result.getMetadata()); + + ((BasicManagedBundle)result.getMetadata()).setPersistenceNeeded(true); + mgmt().getRebindManager().getChangeListener().onUnmanaged(result.getMetadata()); } } public void run() { @@ -438,6 +448,9 @@ class OsgiArchiveInstaller { if (itemsFromOldBundle!=null) { // add back all itemsFromOldBundle (when replacing a bundle) for (RegisteredType oldItem: itemsFromOldBundle) { + if (log.isTraceEnabled()) { + log.trace("RESTORING replaced bundle item "+oldItem+"\n"+RegisteredTypes.getImplementationDataStringForSpec(oldItem)); + } ((BasicBrooklynTypeRegistry)mgmt().getTypeRegistry()).addToLocalUnpersistedTypeRegistry(oldItem, true); } } @@ -447,7 +460,12 @@ class OsgiArchiveInstaller { // in reverse order so if other bundle adds multiple we end up with the real original Collections.reverse(replaced); for (RegisteredType oldItem: replaced) { - ((BasicBrooklynTypeRegistry)mgmt().getTypeRegistry()).addToLocalUnpersistedTypeRegistry(oldItem, true); + if (oldItem!=null) { + if (log.isTraceEnabled()) { + log.trace("RESTORING replaced external item "+oldItem+"\n"+RegisteredTypes.getImplementationDataStringForSpec(oldItem)); + } + ((BasicBrooklynTypeRegistry)mgmt().getTypeRegistry()).addToLocalUnpersistedTypeRegistry(oldItem, true); + } } } http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e8e39fd7/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/OsgiManager.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/OsgiManager.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/OsgiManager.java index 18a2b33..111dfcc 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/OsgiManager.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/OsgiManager.java @@ -19,6 +19,9 @@ package org.apache.brooklyn.core.mgmt.ha; import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.util.Arrays; @@ -61,6 +64,7 @@ import org.apache.brooklyn.util.os.Os; import org.apache.brooklyn.util.os.Os.DeletionResult; import org.apache.brooklyn.util.osgi.VersionedName; import org.apache.brooklyn.util.repeat.Repeater; +import org.apache.brooklyn.util.stream.Streams; import org.apache.brooklyn.util.text.Strings; import org.apache.brooklyn.util.time.Duration; import org.osgi.framework.Bundle; @@ -99,14 +103,17 @@ public class OsgiManager { private boolean reuseFramework; private Set<Bundle> bundlesAtStartup; - private File osgiCacheDir; + /** Used by us to store bundle ZIPs; can be deleted between server runs, repopulated by rebind. */ + private File brooklynBundlesCacheDir; + /** Given to OSGi container for use as its framework cache */ + private File osgiFrameworkCacheDir; final ManagedBundlesRecord managedBundlesRecord = new ManagedBundlesRecord(); - final Map<VersionedName,ManagedBundle> wrapperBundles = MutableMap.of(); - static class ManagedBundlesRecord { - private Map<String, ManagedBundle> managedBundlesByUid = MutableMap.of(); - private Map<VersionedName, String> managedBundlesUidByVersionedName = MutableMap.of(); - private Map<String, String> managedBundlesUidByUrl = MutableMap.of(); + class ManagedBundlesRecord { + private final Map<String, ManagedBundle> managedBundlesByUid = MutableMap.of(); + private final Map<VersionedName, String> managedBundlesUidByVersionedName = MutableMap.of(); + private final Map<String, String> managedBundlesUidByUrl = MutableMap.of(); + private final Map<VersionedName,ManagedBundle> wrapperBundles = MutableMap.of(); synchronized Map<String, ManagedBundle> getManagedBundles() { return ImmutableMap.copyOf(managedBundlesByUid); @@ -134,7 +141,8 @@ public class OsgiManager { managedBundlesUidByUrl.put(url, id); } - synchronized void addManagedBundle(OsgiBundleInstallationResult result) { + synchronized void addManagedBundle(OsgiBundleInstallationResult result, File f) { + updateManagedBundleFile(result, f); managedBundlesByUid.put(result.getMetadata().getId(), result.getMetadata()); managedBundlesUidByVersionedName.put(VersionedName.toOsgiVersionedName(result.getMetadata().getVersionedName()), result.getMetadata().getId()); @@ -142,6 +150,55 @@ public class OsgiManager { managedBundlesUidByUrl.put(result.getMetadata().getUrl(), result.getMetadata().getId()); } } + + private File fileFor(ManagedBundle managedBundle) { + return new File(brooklynBundlesCacheDir, managedBundle.getId()+"-"+managedBundle.getVersionedName().toOsgiString()+".jar"); + } + + synchronized void addInstalledWrapperBundle(ManagedBundle mb) { + wrapperBundles.put(mb.getVersionedName(), mb); + } + private synchronized void removeInstalledWrapperBundle(ManagedBundle mb) { + wrapperBundles.remove(mb.getVersionedName()); + } + + synchronized boolean remove(ManagedBundle bundleMetadata) { + ManagedBundle metadata = managedBundlesRecord.managedBundlesByUid.remove(bundleMetadata.getId()); + if (metadata==null) { + return false; + } + managedBundlesRecord.managedBundlesUidByVersionedName.remove(bundleMetadata.getVersionedName()); + managedBundlesRecord.managedBundlesUidByUrl.remove(bundleMetadata.getUrl()); + removeInstalledWrapperBundle(bundleMetadata); + fileFor(bundleMetadata).delete(); + return true; + } + + /** Updates the bundle file associated with the given record, creating and returning a backup if there was already such a file */ + synchronized File updateManagedBundleFile(OsgiBundleInstallationResult result, File fNew) { + File fCached = fileFor(result.getMetadata()); + File fBak = null; + if (fCached.exists()) { + fBak = new File(fCached.getAbsolutePath()+".bak"); + if (fBak.equals(fNew)) { + // rolling back + log.debug("Rolling back to back Brooklyn local copy of bundle file "+fCached); + fCached.delete(); + fBak.renameTo(fCached); + return null; + } + log.debug("Replacing and backing up old Brooklyn local copy of bundle file "+fCached); + fCached.renameTo(fBak); + } else { + log.debug("Creating Brooklyn local copy of bundle file "+fCached); + } + try (FileInputStream fin = new FileInputStream(fNew); FileOutputStream fout = new FileOutputStream(fCached)) { + Streams.copy(fin, fout); + } catch (IOException e) { + throw Exceptions.propagate(e); + } + return fBak; + } } private static AtomicInteger numberOfReusableFrameworksCreated = new AtomicInteger(); @@ -158,6 +215,9 @@ public class OsgiManager { } try { + brooklynBundlesCacheDir = Os.newTempDir("brooklyn-osgi-brooklyn-bundles-cache"); + Os.deleteOnExitRecursively(brooklynBundlesCacheDir); + if (mgmt.getConfig().getConfig(REUSE_OSGI)) { reuseFramework = true; @@ -177,19 +237,19 @@ public class OsgiManager { return; } - osgiCacheDir = Os.newTempDir("brooklyn-osgi-reusable-container"); - Os.deleteOnExitRecursively(osgiCacheDir); + osgiFrameworkCacheDir = Os.newTempDir("brooklyn-osgi-reusable-container"); + Os.deleteOnExitRecursively(osgiFrameworkCacheDir); if (numberOfReusableFrameworksCreated.incrementAndGet()%10==0) { log.warn("Possible leak of reusable OSGi containers ("+numberOfReusableFrameworksCreated+" total)"); } } else { - osgiCacheDir = BrooklynServerPaths.getOsgiCacheDirCleanedIfNeeded(mgmt); + osgiFrameworkCacheDir = BrooklynServerPaths.getOsgiCacheDirCleanedIfNeeded(mgmt); } // any extra OSGi startup args could go here - framework = Osgis.getFramework(osgiCacheDir.getAbsolutePath(), false); - log.debug("OSGi framework container created in "+osgiCacheDir+" mgmt node "+mgmt.getManagementNodeId()+ + framework = Osgis.getFramework(osgiFrameworkCacheDir.getAbsolutePath(), false); + log.debug("OSGi framework container created in "+osgiFrameworkCacheDir+" mgmt node "+mgmt.getManagementNodeId()+ (reuseFramework ? "(reusable, "+numberOfReusableFrameworksCreated.get()+" total)" : "") ); } catch (Exception e) { @@ -227,7 +287,7 @@ public class OsgiManager { OSGI_FRAMEWORK_CONTAINERS_FOR_REUSE.add(framework); } - } else if (BrooklynServerPaths.isOsgiCacheForCleaning(mgmt, osgiCacheDir)) { + } else if (BrooklynServerPaths.isOsgiCacheForCleaning(mgmt, osgiFrameworkCacheDir)) { // See exception reported in https://issues.apache.org/jira/browse/BROOKLYN-72 // We almost always fail to delete he OSGi temp directory due to a concurrent modification. // Therefore keep trying. @@ -236,18 +296,21 @@ public class OsgiManager { .until(new Callable<Boolean>() { @Override public Boolean call() { - deletionResult.set(Os.deleteRecursively(osgiCacheDir)); + deletionResult.set(Os.deleteRecursively(osgiFrameworkCacheDir)); return deletionResult.get().wasSuccessful(); }}) .limitTimeTo(Duration.ONE_SECOND) .backoffTo(Duration.millis(50)) .run(); if (deletionResult.get().getThrowable()!=null) { - log.debug("Unable to delete "+osgiCacheDir+" (possibly being modified concurrently?): "+deletionResult.get().getThrowable()); + log.debug("Unable to delete "+osgiFrameworkCacheDir+" (possibly being modified concurrently?): "+deletionResult.get().getThrowable()); } } - osgiCacheDir = null; + osgiFrameworkCacheDir = null; framework = null; + + Os.deleteRecursively(brooklynBundlesCacheDir); + brooklynBundlesCacheDir = null; } /** Map of bundles by UID */ @@ -310,18 +373,13 @@ public class OsgiManager { * Callers should typically fail if anything from this bundle is in use. */ public void uninstallUploadedBundle(ManagedBundle bundleMetadata) { - synchronized (managedBundlesRecord) { - ManagedBundle metadata = managedBundlesRecord.managedBundlesByUid.remove(bundleMetadata.getId()); - if (metadata==null) { - throw new IllegalStateException("No such bundle registered: "+bundleMetadata); - } - managedBundlesRecord.managedBundlesUidByVersionedName.remove(bundleMetadata.getVersionedName()); - managedBundlesRecord.managedBundlesUidByUrl.remove(bundleMetadata.getUrl()); - removeInstalledWrapperBundle(bundleMetadata); + uninstallCatalogItemsFromBundle( bundleMetadata.getVersionedName() ); + + if (!managedBundlesRecord.remove(bundleMetadata)) { + throw new IllegalStateException("No such bundle registered: "+bundleMetadata); } mgmt.getRebindManager().getChangeListener().onUnmanaged(bundleMetadata); - uninstallCatalogItemsFromBundle( bundleMetadata.getVersionedName() ); Bundle bundle = framework.getBundleContext().getBundle(bundleMetadata.getOsgiUniqueUrl()); if (bundle==null) { @@ -590,19 +648,16 @@ public class OsgiManager { // track wrapper bundles lifecvcle specially, to avoid removing it while it's installing public void addInstalledWrapperBundle(ManagedBundle mb) { - synchronized (wrapperBundles) { - wrapperBundles.put(mb.getVersionedName(), mb); - } - } - public void removeInstalledWrapperBundle(ManagedBundle mb) { - synchronized (wrapperBundles) { - wrapperBundles.remove(mb.getVersionedName()); - } + managedBundlesRecord.addInstalledWrapperBundle(mb); } public Collection<ManagedBundle> getInstalledWrapperBundles() { - synchronized (wrapperBundles) { - return MutableSet.copyOf(wrapperBundles.values()); + synchronized (managedBundlesRecord) { + return MutableSet.copyOf(managedBundlesRecord.wrapperBundles.values()); } } + public File getBundleFile(ManagedBundle mb) { + return managedBundlesRecord.fileFor(mb); + } + } http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e8e39fd7/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/BrooklynMementoPersisterToObjectStore.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/BrooklynMementoPersisterToObjectStore.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/BrooklynMementoPersisterToObjectStore.java index e8bb5fc..07abf6b 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/BrooklynMementoPersisterToObjectStore.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/BrooklynMementoPersisterToObjectStore.java @@ -20,7 +20,6 @@ package org.apache.brooklyn.core.mgmt.persist; import static com.google.common.base.Preconditions.checkNotNull; -import java.io.File; import java.io.IOException; import java.util.LinkedHashMap; import java.util.List; @@ -76,6 +75,7 @@ import org.apache.brooklyn.util.time.Duration; import org.apache.brooklyn.util.time.Time; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.w3c.dom.NodeList; import com.google.common.annotations.Beta; import com.google.common.base.Objects; @@ -87,7 +87,6 @@ import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListeningExecutorService; import com.google.common.util.concurrent.MoreExecutors; -import org.w3c.dom.NodeList; /** Implementation of the {@link BrooklynMementoPersister} backed by a pluggable * {@link PersistenceObjectStore} such as a file system or a jclouds object store */ @@ -338,8 +337,11 @@ public class BrooklynMementoPersisterToObjectStore implements BrooklynMementoPer LOG.warn("ID mismatch on "+type.toCamelCase()+", "+id+" from path, "+safeXmlId+" from xml"); if (type == BrooklynObjectType.MANAGED_BUNDLE) { - // TODO write to temp file, destroy when loaded + // TODO could R/W to cache space directly, rather than memory copy then extra file copy byte[] jarData = readBytes(contentsSubpath+".jar"); + if (jarData==null) { + throw new IllegalStateException("No bundle data for "+contentsSubpath); + } builder.bundleJar(id, ByteSource.wrap(jarData)); } builder.put(type, xmlId, contents); @@ -713,19 +715,17 @@ public class BrooklynMementoPersisterToObjectStore implements BrooklynMementoPer } if (mb instanceof BasicManagedBundle) { - final File f = ((BasicManagedBundle)mb).getTempLocalFileWhenJustUploaded(); - // use the above transient field to know when to upload - if (f!=null) { + if (((BasicManagedBundle)mb).getPersistenceNeeded()) { futures.add( executor.submit(new Runnable() { @Override public void run() { - if (((BasicManagedBundle)mb).getTempLocalFileWhenJustUploaded()==null) { + if (!((BasicManagedBundle)mb).getPersistenceNeeded()) { // someone else persisted this (race) return; } - persist(type.getSubPathName(), type, id+".jar", com.google.common.io.Files.asByteSource(f), exceptionHandler); - ((BasicManagedBundle)mb).setTempLocalFileWhenJustUploaded(null); - f.delete(); + persist(type.getSubPathName(), type, id+".jar", com.google.common.io.Files.asByteSource( + ((ManagementContextInternal)mgmt).getOsgiManager().get().getBundleFile(mb)), exceptionHandler); + ((BasicManagedBundle)mb).setPersistenceNeeded(false); } }) ); } } http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e8e39fd7/core/src/main/java/org/apache/brooklyn/core/typereg/BasicManagedBundle.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/typereg/BasicManagedBundle.java b/core/src/main/java/org/apache/brooklyn/core/typereg/BasicManagedBundle.java index 19c1699..253f3a6 100644 --- a/core/src/main/java/org/apache/brooklyn/core/typereg/BasicManagedBundle.java +++ b/core/src/main/java/org/apache/brooklyn/core/typereg/BasicManagedBundle.java @@ -18,7 +18,6 @@ */ package org.apache.brooklyn.core.typereg; -import java.io.File; import java.util.Map; import org.apache.brooklyn.api.catalog.CatalogItem.CatalogBundle; @@ -32,7 +31,6 @@ import org.apache.brooklyn.core.objs.BrooklynObjectInternal; import org.apache.brooklyn.util.osgi.VersionedName; import org.apache.brooklyn.util.text.BrooklynVersionSyntax; -import com.google.common.annotations.Beta; import com.google.common.base.MoreObjects; import com.google.common.base.Objects; import com.google.common.base.Preconditions; @@ -43,7 +41,7 @@ public class BasicManagedBundle extends AbstractBrooklynObject implements Manage private String version; private String checksum; private String url; - private transient File localFileWhenJustUploaded; + private transient boolean persistenceNeeded = false; /** Creates an empty one, with an ID, expecting other fields will be populated. */ public BasicManagedBundle() {} @@ -103,16 +101,6 @@ public class BasicManagedBundle extends AbstractBrooklynObject implements Manage this.url = url; } - /** This is cached on the object when just uploaded, then deleted after it has been persisted. */ - @Beta - public void setTempLocalFileWhenJustUploaded(File localFileWhenJustUploaded) { - this.localFileWhenJustUploaded = localFileWhenJustUploaded; - } - @Beta - public File getTempLocalFileWhenJustUploaded() { - return localFileWhenJustUploaded; - } - @Override public String getOsgiUniqueUrl() { return "brooklyn:"+getId(); @@ -204,4 +192,13 @@ public class BasicManagedBundle extends AbstractBrooklynObject implements Manage public static ManagedBundle of(CatalogBundle bundleUrl) { return new BasicManagedBundle(bundleUrl.getSymbolicName(), bundleUrl.getSuppliedVersionString(), bundleUrl.getUrl()); } + + public void setPersistenceNeeded(boolean val) { + persistenceNeeded |= val; + } + public boolean getPersistenceNeeded() { + return persistenceNeeded; + + } + }
