Modified the bundle archive implementation to reconstruct old bundle
revisions if they exist in the file system on startup. Such a situation
occurs if a bundle was updated and the framework uncleanly exited before
a refresh was performed. By recreating the existing revisions, the
framework will force a purge at startup to delete the old revision
directories and only keep the most recent revision (just as if a normal
refresh has occurred instead of an unclean exit in the previous session).
git-svn-id: https://svn.apache.org/repos/asf/incubator/felix/trunk@405419 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/cache/BundleArchive.java b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/cache/BundleArchive.java
index e5f6fbf..5c1d24c 100644
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/cache/BundleArchive.java
+++ b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/cache/BundleArchive.java
@@ -157,7 +157,40 @@
m_logger = logger;
m_archiveRootDir = archiveRootDir;
- // Add a revision for the content.
+ // Add a revision for each one that already exists in the file
+ // system. The file system might contain more than one revision
+ // if the bundle was updated in a previous session, but the
+ // framework was not refreshed; this might happen if the framework
+ // did not exit cleanly. We must create the existing revisions so
+ // that they can be properly purged.
+ int revisionCount = 0;
+ while (true)
+ {
+ // Count the number of existing revision directories, which
+ // will be in a directory named like:
+ // "${REVISION_DIRECTORY)${refresh-count}.${revision-count}"
+ File revisionRootDir = new File(m_archiveRootDir,
+ REVISION_DIRECTORY + getRefreshCount() + "." + revisionCount);
+ if (!BundleCache.getSecureAction().fileExists(revisionRootDir))
+ {
+ break;
+ }
+
+ // Increment the revision count.
+ revisionCount++;
+ }
+
+ // If there are multiple revisions in the file system, then create
+ // an array that is big enough to hold all revisions minus one; the
+ // call below to revise() will add the most recent revision. NOTE: We
+ // do not actually need to add a real revision object for the older
+ // revisions since they will be purged immediately on framework startup.
+ if (revisionCount > 1)
+ {
+ m_revisions = new BundleRevision[revisionCount - 1];
+ }
+
+ // Add the revision object for the most recent revision.
revise(getCurrentLocation(), null);
}
@@ -619,7 +652,14 @@
File revisionDir = null;
for (int i = 0; i < count - 1; i++)
{
- m_revisions[i].dispose();
+ // Dispose of the revision, but this might be null in certain
+ // circumstances, such as if this bundle archive was created
+ // for an existing bundle that was updated, but not refreshed
+ // due to a system crash; see the constructor code for details.
+ if (m_revisions[i] != null)
+ {
+ m_revisions[i].dispose();
+ }
revisionDir = new File(m_archiveRootDir, REVISION_DIRECTORY + refreshCount + "." + i);
if (BundleCache.getSecureAction().fileExists(revisionDir))
{
@@ -797,7 +837,7 @@
private BundleRevision createRevisionFromLocation(String location, InputStream is)
throws Exception
{
- // The revision directory is name using the refresh count and
+ // The revision directory is named using the refresh count and
// the revision count. The revision count is obvious, but the
// refresh count is less obvious. This is necessary due to how
// native libraries are handled in Java; needless to say, every
diff --git a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/cache/JarRevision.java b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/cache/JarRevision.java
index cbba4b1..22423b6 100644
--- a/org.apache.felix.framework/src/main/java/org/apache/felix/framework/cache/JarRevision.java
+++ b/org.apache.felix.framework/src/main/java/org/apache/felix/framework/cache/JarRevision.java
@@ -259,7 +259,7 @@
return;
}
- // Create revision directory, if it does not exist.
+ // Create revision directory.
if (!BundleCache.getSecureAction().mkdir(getRevisionRootDir()))
{
getLogger().log(
@@ -297,7 +297,6 @@
BundleCache.copyStreamToFile(is, m_bundleFile);
}
- // This will always be revision zero.
preprocessBundleJar();
}
finally