Improve cache handling by combining state stored in separate files into
a single file. This helps performance as well as cleans up some of the
code. (FELIX-2619, FELIX-2626)
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1003559 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/framework/src/main/java/org/apache/felix/framework/Felix.java b/framework/src/main/java/org/apache/felix/framework/Felix.java
index 62ac4ab..3e2619b 100644
--- a/framework/src/main/java/org/apache/felix/framework/Felix.java
+++ b/framework/src/main/java/org/apache/felix/framework/Felix.java
@@ -2461,7 +2461,7 @@
try
{
// Add the bundle to the cache.
- ba = m_cache.create(id, location, is);
+ ba = m_cache.create(id, location, getInitialBundleStartLevel(), is);
}
catch (Exception ex)
{
@@ -2577,15 +2577,6 @@
}
}
- // If the bundle is new, then set its start level; existing
- // bundles already have their start level set.
- if (isNew)
- {
- // This will persistently set the bundle's start level.
- bundle.setStartLevel(getInitialBundleStartLevel());
- bundle.setLastModified(System.currentTimeMillis());
- }
-
// Acquire global lock.
boolean locked = acquireGlobalLock();
if (!locked)
diff --git a/framework/src/main/java/org/apache/felix/framework/cache/BundleArchive.java b/framework/src/main/java/org/apache/felix/framework/cache/BundleArchive.java
index e46d7e7..996c7a7 100644
--- a/framework/src/main/java/org/apache/felix/framework/cache/BundleArchive.java
+++ b/framework/src/main/java/org/apache/felix/framework/cache/BundleArchive.java
@@ -67,32 +67,24 @@
public static final transient String REFERENCE_PROTOCOL = "reference:";
public static final transient String INPUTSTREAM_PROTOCOL = "inputstream:";
- private static final transient String BUNDLE_ID_FILE = "bundle.id";
- private static final transient String BUNDLE_LOCATION_FILE = "bundle.location";
+ private static final transient String BUNDLE_INFO_FILE = "bundle.info";
private static final transient String REVISION_LOCATION_FILE = "revision.location";
- private static final transient String BUNDLE_STATE_FILE = "bundle.state";
- private static final transient String BUNDLE_START_LEVEL_FILE = "bundle.startlevel";
- private static final transient String REFRESH_COUNTER_FILE = "refresh.counter";
- private static final transient String BUNDLE_LASTMODIFIED_FILE = "bundle.lastmodified";
private static final transient String REVISION_DIRECTORY = "version";
private static final transient String DATA_DIRECTORY = "data";
- private static final transient String ACTIVE_STATE = "active";
- private static final transient String STARTING_STATE = "starting";
- private static final transient String INSTALLED_STATE = "installed";
- private static final transient String UNINSTALLED_STATE = "uninstalled";
private final Logger m_logger;
private final Map m_configMap;
- private long m_id = -1;
private final File m_archiveRootDir;
+
+ private long m_id = -1;
private String m_originalLocation = null;
private int m_persistentState = -1;
private int m_startLevel = -1;
private long m_lastModified = -1;
- private BundleRevision[] m_revisions = null;
-
private long m_refreshCount = -1;
+ private BundleRevision[] m_revisions = null;
+
/**
* <p>
* This constructor is only used by the system bundle archive implementation
@@ -124,7 +116,7 @@
* @throws Exception if any error occurs.
**/
public BundleArchive(Logger logger, Map configMap, File archiveRootDir, long id,
- String location, InputStream is) throws Exception
+ String location, int startLevel, InputStream is) throws Exception
{
m_logger = logger;
m_configMap = configMap;
@@ -136,6 +128,10 @@
"Bundle ID cannot be less than or equal to zero.");
}
m_originalLocation = location;
+ m_persistentState = Bundle.INSTALLED;
+ m_startLevel = startLevel;
+ m_lastModified = System.currentTimeMillis();
+ m_refreshCount = 0;
// Save state.
initialize();
@@ -163,6 +159,9 @@
m_configMap = configMap;
m_archiveRootDir = archiveRootDir;
+ // Read previously saved state.
+ readBundleInfo();
+
// 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
@@ -212,36 +211,6 @@
**/
public synchronized long getId() throws Exception
{
- if (m_id <= 0)
- {
- // Read bundle location.
- InputStream is = null;
- BufferedReader br = null;
- try
- {
- is = BundleCache.getSecureAction()
- .getFileInputStream(new File(m_archiveRootDir, BUNDLE_ID_FILE));
- br = new BufferedReader(new InputStreamReader(is));
- m_id = Long.parseLong(br.readLine());
- }
- catch (FileNotFoundException ex)
- {
- // HACK: Get the bundle identifier from the archive root directory
- // name, which is of the form "bundle<id>" where <id> is the bundle
- // identifier numbers. This is a hack to deal with old archives that
- // did not save their bundle identifier, but instead had it passed
- // into them. Eventually, this can be removed.
- m_id = Long.parseLong(
- m_archiveRootDir.getName().substring(
- BundleCache.BUNDLE_DIR_PREFIX.length()));
- }
- finally
- {
- if (br != null) br.close();
- if (is != null) is.close();
- }
- }
-
return m_id;
}
@@ -254,24 +223,6 @@
**/
public synchronized String getLocation() throws Exception
{
- if (m_originalLocation == null)
- {
- // Read bundle location.
- InputStream is = null;
- BufferedReader br = null;
- try
- {
- is = BundleCache.getSecureAction()
- .getFileInputStream(new File(m_archiveRootDir, BUNDLE_LOCATION_FILE));
- br = new BufferedReader(new InputStreamReader(is));
- m_originalLocation = br.readLine();
- }
- finally
- {
- if (br != null) br.close();
- if (is != null) is.close();
- }
- }
return m_originalLocation;
}
@@ -286,52 +237,6 @@
**/
public synchronized int getPersistentState() throws Exception
{
- if (m_persistentState < 0)
- {
- // Get bundle state file.
- File stateFile = new File(m_archiveRootDir, BUNDLE_STATE_FILE);
-
- // If the state file doesn't exist, then
- // assume the bundle was installed.
- if (!BundleCache.getSecureAction().fileExists(stateFile))
- {
- m_persistentState = Bundle.INSTALLED;
- }
- else
- {
- // Read the bundle state.
- InputStream is = null;
- BufferedReader br = null;
- try
- {
- is = BundleCache.getSecureAction()
- .getFileInputStream(stateFile);
- br = new BufferedReader(new InputStreamReader(is));
- String s = br.readLine();
- if ((s != null) && s.equals(ACTIVE_STATE))
- {
- m_persistentState = Bundle.ACTIVE;
- }
- else if ((s != null) && s.equals(STARTING_STATE))
- {
- m_persistentState = Bundle.STARTING;
- }
- else if ((s != null) && s.equals(UNINSTALLED_STATE))
- {
- m_persistentState = Bundle.UNINSTALLED;
- }
- else
- {
- m_persistentState = Bundle.INSTALLED;
- }
- }
- finally
- {
- if (br != null) br.close();
- if (is != null) is.close();
- }
- }
- }
return m_persistentState;
}
@@ -346,47 +251,10 @@
**/
public synchronized void setPersistentState(int state) throws Exception
{
- // Write the bundle state.
- OutputStream os = null;
- BufferedWriter bw = null;
if (m_persistentState != state)
{
- try
- {
- os = BundleCache.getSecureAction()
- .getFileOutputStream(new File(m_archiveRootDir, BUNDLE_STATE_FILE));
- bw = new BufferedWriter(new OutputStreamWriter(os));
- String s = null;
- switch (state)
- {
- case Bundle.ACTIVE:
- s = ACTIVE_STATE;
- break;
- case Bundle.STARTING:
- s = STARTING_STATE;
- break;
- case Bundle.UNINSTALLED:
- s = UNINSTALLED_STATE;
- break;
- default:
- s = INSTALLED_STATE;
- break;
- }
- bw.write(s, 0, s.length());
- m_persistentState = state;
- }
- catch (IOException ex)
- {
- m_logger.log(
- Logger.LOG_ERROR,
- getClass().getName() + ": Unable to record state - " + ex);
- throw ex;
- }
- finally
- {
- if (bw != null) bw.close();
- if (os != null) os.close();
- }
+ m_persistentState = state;
+ writeBundleInfo();
}
}
@@ -399,36 +267,6 @@
**/
public synchronized int getStartLevel() throws Exception
{
- if (m_startLevel < 0)
- {
- // Get bundle start level file.
- File levelFile = new File(m_archiveRootDir, BUNDLE_START_LEVEL_FILE);
-
- // If the start level file doesn't exist, then
- // return an error.
- if (!BundleCache.getSecureAction().fileExists(levelFile))
- {
- m_startLevel = -1;
- }
- else
- {
- // Read the bundle start level.
- InputStream is = null;
- BufferedReader br= null;
- try
- {
- is = BundleCache.getSecureAction()
- .getFileInputStream(levelFile);
- br = new BufferedReader(new InputStreamReader(is));
- m_startLevel = Integer.parseInt(br.readLine());
- }
- finally
- {
- if (br != null) br.close();
- if (is != null) is.close();
- }
- }
- }
return m_startLevel;
}
@@ -441,29 +279,10 @@
**/
public synchronized void setStartLevel(int level) throws Exception
{
- // Write the bundle start level.
- OutputStream os = null;
- BufferedWriter bw = null;
- try
+ if (m_startLevel != level)
{
- os = BundleCache.getSecureAction()
- .getFileOutputStream(new File(m_archiveRootDir, BUNDLE_START_LEVEL_FILE));
- bw = new BufferedWriter(new OutputStreamWriter(os));
- String s = Integer.toString(level);
- bw.write(s, 0, s.length());
m_startLevel = level;
- }
- catch (IOException ex)
- {
- m_logger.log(
- Logger.LOG_ERROR,
- getClass().getName() + ": Unable to record start level - " + ex);
- throw ex;
- }
- finally
- {
- if (bw != null) bw.close();
- if (os != null) os.close();
+ writeBundleInfo();
}
}
@@ -476,35 +295,6 @@
**/
public synchronized long getLastModified() throws Exception
{
- if (m_lastModified < 0)
- {
- // Get bundle last modification time file.
- File lastModFile = new File(m_archiveRootDir, BUNDLE_LASTMODIFIED_FILE);
-
- // If the last modification file doesn't exist, then
- // return an error.
- if (!BundleCache.getSecureAction().fileExists(lastModFile))
- {
- m_lastModified = 0;
- }
- else
- {
- // Read the bundle start level.
- InputStream is = null;
- BufferedReader br= null;
- try
- {
- is = BundleCache.getSecureAction().getFileInputStream(lastModFile);
- br = new BufferedReader(new InputStreamReader(is));
- m_lastModified = Long.parseLong(br.readLine());
- }
- finally
- {
- if (br != null) br.close();
- if (is != null) is.close();
- }
- }
- }
return m_lastModified;
}
@@ -520,29 +310,10 @@
**/
public synchronized void setLastModified(long lastModified) throws Exception
{
- // Write the bundle last modification time.
- OutputStream os = null;
- BufferedWriter bw = null;
- try
+ if (m_lastModified != lastModified)
{
- os = BundleCache.getSecureAction()
- .getFileOutputStream(new File(m_archiveRootDir, BUNDLE_LASTMODIFIED_FILE));
- bw = new BufferedWriter(new OutputStreamWriter(os));
- String s = Long.toString(lastModified);
- bw.write(s, 0, s.length());
m_lastModified = lastModified;
- }
- catch (IOException ex)
- {
- m_logger.log(
- Logger.LOG_ERROR,
- getClass().getName() + ": Unable to record last modification time - " + ex);
- throw ex;
- }
- finally
- {
- if (bw != null) bw.close();
- if (os != null) os.close();
+ writeBundleInfo();
}
}
@@ -860,19 +631,7 @@
throw new IOException("Unable to create archive directory.");
}
- // Save id.
- os = BundleCache.getSecureAction()
- .getFileOutputStream(new File(m_archiveRootDir, BUNDLE_ID_FILE));
- bw = new BufferedWriter(new OutputStreamWriter(os));
- bw.write(Long.toString(m_id), 0, Long.toString(m_id).length());
- bw.close();
- os.close();
-
- // Save location string.
- os = BundleCache.getSecureAction()
- .getFileOutputStream(new File(m_archiveRootDir, BUNDLE_LOCATION_FILE));
- bw = new BufferedWriter(new OutputStreamWriter(os));
- bw.write(m_originalLocation, 0, m_originalLocation.length());
+ writeBundleInfo();
}
finally
{
@@ -1028,39 +787,6 @@
**/
private long getRefreshCount() throws Exception
{
- // If the refresh counter is not yet initialized, do so now.
- if (m_refreshCount < 0)
- {
- // Get refresh counter file.
- File counterFile = new File(m_archiveRootDir, REFRESH_COUNTER_FILE);
-
- // If the refresh counter file doesn't exist, then
- // assume the counter is at zero.
- if (!BundleCache.getSecureAction().fileExists(counterFile))
- {
- m_refreshCount = 0;
- }
- else
- {
- // Read the bundle refresh counter.
- InputStream is = null;
- BufferedReader br = null;
- try
- {
- is = BundleCache.getSecureAction()
- .getFileInputStream(counterFile);
- br = new BufferedReader(new InputStreamReader(is));
- long counter = Long.parseLong(br.readLine());
- return counter;
- }
- finally
- {
- if (br != null) br.close();
- if (is != null) is.close();
- }
- }
- }
-
return m_refreshCount;
}
@@ -1078,29 +804,102 @@
* As a result of the unique name, the JVM will then reload the
* native library without a problem.
**/
- private void setRefreshCount(long counter)
+ private void setRefreshCount(long count)
throws Exception
{
- // Get refresh counter file.
- File counterFile = new File(m_archiveRootDir, REFRESH_COUNTER_FILE);
+ if (m_refreshCount != count)
+ {
+ m_refreshCount = count;
+ writeBundleInfo();
+ }
+ }
- // Write the refresh counter.
+ private void readBundleInfo() throws Exception
+ {
+ File infoFile = new File(m_archiveRootDir, BUNDLE_INFO_FILE);
+
+ // Read the bundle start level.
+ InputStream is = null;
+ BufferedReader br= null;
+ try
+ {
+ is = BundleCache.getSecureAction()
+ .getFileInputStream(infoFile);
+ br = new BufferedReader(new InputStreamReader(is));
+
+ // Read id.
+ m_id = Long.parseLong(br.readLine());
+ // Read location.
+ m_originalLocation = br.readLine();
+ // Read state.
+ m_persistentState = Integer.parseInt(br.readLine());
+ // Read start level.
+ m_startLevel = Integer.parseInt(br.readLine());
+ // Read last modified.
+ m_lastModified = Long.parseLong(br.readLine());
+ // Read refresh count.
+ m_refreshCount = Long.parseLong(br.readLine());
+ }
+ catch (FileNotFoundException ex)
+ {
+ // If there wasn't an info file, then maybe this is an old-style
+ // bundle cache, so try to read the files individually. We can
+ // delete this eventually.
+ m_id = readId();
+ m_originalLocation = readLocation();
+ m_persistentState = readPersistentState();
+ m_startLevel = readStartLevel();
+ m_lastModified = readLastModified();
+ m_refreshCount = readRefreshCount();
+ }
+ finally
+ {
+ if (br != null) br.close();
+ if (is != null) is.close();
+ }
+ }
+
+ private void writeBundleInfo() throws Exception
+ {
+ // Write the bundle start level.
OutputStream os = null;
BufferedWriter bw = null;
try
{
os = BundleCache.getSecureAction()
- .getFileOutputStream(counterFile);
+ .getFileOutputStream(new File(m_archiveRootDir, BUNDLE_INFO_FILE));
bw = new BufferedWriter(new OutputStreamWriter(os));
- String s = Long.toString(counter);
+
+ // Write id.
+ String s = Long.toString(m_id);
bw.write(s, 0, s.length());
- m_refreshCount = counter;
+ bw.newLine();
+ // Write location.
+ s = (m_originalLocation == null) ? "" : m_originalLocation;
+ bw.write(s, 0, s.length());
+ bw.newLine();
+ // Write state.
+ s = Integer.toString(m_persistentState);
+ bw.write(s, 0, s.length());
+ bw.newLine();
+ // Write start level.
+ s = Integer.toString(m_startLevel);
+ bw.write(s, 0, s.length());
+ bw.newLine();
+ // Write last modified.
+ s = Long.toString(m_lastModified);
+ bw.write(s, 0, s.length());
+ bw.newLine();
+ // Write refresh count.
+ s = Long.toString(m_refreshCount);
+ bw.write(s, 0, s.length());
+ bw.newLine();
}
catch (IOException ex)
{
m_logger.log(
Logger.LOG_ERROR,
- getClass().getName() + ": Unable to write refresh counter: " + ex);
+ getClass().getName() + ": Unable to cache bundle info - " + ex);
throw ex;
}
finally
@@ -1109,4 +908,207 @@
if (os != null) os.close();
}
}
+
+ //
+ // Deprecated bundle cache format to be deleted eventually.
+ //
+
+ private static final transient String BUNDLE_ID_FILE = "bundle.id";
+ private static final transient String BUNDLE_LOCATION_FILE = "bundle.location";
+ private static final transient String BUNDLE_STATE_FILE = "bundle.state";
+ private static final transient String BUNDLE_START_LEVEL_FILE = "bundle.startlevel";
+ private static final transient String BUNDLE_LASTMODIFIED_FILE = "bundle.lastmodified";
+ private static final transient String REFRESH_COUNTER_FILE = "refresh.counter";
+
+ private long readId() throws Exception
+ {
+ long id;
+
+ InputStream is = null;
+ BufferedReader br = null;
+ try
+ {
+ is = BundleCache.getSecureAction()
+ .getFileInputStream(new File(m_archiveRootDir, BUNDLE_ID_FILE));
+ br = new BufferedReader(new InputStreamReader(is));
+ id = Long.parseLong(br.readLine());
+ }
+ catch (FileNotFoundException ex)
+ {
+ // HACK: Get the bundle identifier from the archive root directory
+ // name, which is of the form "bundle<id>" where <id> is the bundle
+ // identifier numbers. This is a hack to deal with old archives that
+ // did not save their bundle identifier, but instead had it passed
+ // into them. Eventually, this can be removed.
+ id = Long.parseLong(
+ m_archiveRootDir.getName().substring(
+ BundleCache.BUNDLE_DIR_PREFIX.length()));
+ }
+ finally
+ {
+ if (br != null) br.close();
+ if (is != null) is.close();
+ }
+
+ return id;
+ }
+
+ private String readLocation() throws Exception
+ {
+ InputStream is = null;
+ BufferedReader br = null;
+ try
+ {
+ is = BundleCache.getSecureAction()
+ .getFileInputStream(new File(m_archiveRootDir, BUNDLE_LOCATION_FILE));
+ br = new BufferedReader(new InputStreamReader(is));
+ return br.readLine();
+ }
+ finally
+ {
+ if (br != null) br.close();
+ if (is != null) is.close();
+ }
+ }
+
+ private static final transient String ACTIVE_STATE = "active";
+ private static final transient String STARTING_STATE = "starting";
+ private static final transient String UNINSTALLED_STATE = "uninstalled";
+
+ private int readPersistentState() throws Exception
+ {
+ int state = Bundle.INSTALLED;
+
+ // Get bundle state file.
+ File stateFile = new File(m_archiveRootDir, BUNDLE_STATE_FILE);
+
+ // If the state file doesn't exist, then
+ // assume the bundle was installed.
+ if (BundleCache.getSecureAction().fileExists(stateFile))
+ {
+ // Read the bundle state.
+ InputStream is = null;
+ BufferedReader br = null;
+ try
+ {
+ is = BundleCache.getSecureAction()
+ .getFileInputStream(stateFile);
+ br = new BufferedReader(new InputStreamReader(is));
+ String s = br.readLine();
+ if ((s != null) && s.equals(ACTIVE_STATE))
+ {
+ state = Bundle.ACTIVE;
+ }
+ else if ((s != null) && s.equals(STARTING_STATE))
+ {
+ state = Bundle.STARTING;
+ }
+ else if ((s != null) && s.equals(UNINSTALLED_STATE))
+ {
+ state = Bundle.UNINSTALLED;
+ }
+ else
+ {
+ state = Bundle.INSTALLED;
+ }
+ }
+ catch (Exception ex)
+ {
+ state = Bundle.INSTALLED;
+ }
+ finally
+ {
+ if (br != null) br.close();
+ if (is != null) is.close();
+ }
+ }
+
+ return state;
+ }
+
+ private int readStartLevel() throws Exception
+ {
+ int level = -1;
+
+ // Get bundle start level file.
+ File levelFile = new File(m_archiveRootDir, BUNDLE_START_LEVEL_FILE);
+
+ // If the start level file doesn't exist, then
+ // return an error.
+ if (!BundleCache.getSecureAction().fileExists(levelFile))
+ {
+ level = -1;
+ }
+ else
+ {
+ // Read the bundle start level.
+ InputStream is = null;
+ BufferedReader br= null;
+ try
+ {
+ is = BundleCache.getSecureAction()
+ .getFileInputStream(levelFile);
+ br = new BufferedReader(new InputStreamReader(is));
+ level = Integer.parseInt(br.readLine());
+ }
+ finally
+ {
+ if (br != null) br.close();
+ if (is != null) is.close();
+ }
+ }
+ return level;
+ }
+
+ private long readLastModified() throws Exception
+ {
+ long last = 0;
+
+ InputStream is = null;
+ BufferedReader br = null;
+ try
+ {
+ is = BundleCache.getSecureAction()
+ .getFileInputStream(new File(m_archiveRootDir, BUNDLE_LASTMODIFIED_FILE));
+ br = new BufferedReader(new InputStreamReader(is));
+ last = Long.parseLong(br.readLine());
+ }
+ catch (Exception ex)
+ {
+ last = 0;
+ }
+ finally
+ {
+ if (br != null) br.close();
+ if (is != null) is.close();
+ }
+
+ return last;
+ }
+
+ private long readRefreshCount() throws Exception
+ {
+ long count = 0;
+
+ InputStream is = null;
+ BufferedReader br = null;
+ try
+ {
+ is = BundleCache.getSecureAction()
+ .getFileInputStream(new File(m_archiveRootDir, REFRESH_COUNTER_FILE));
+ br = new BufferedReader(new InputStreamReader(is));
+ count = Long.parseLong(br.readLine());
+ }
+ catch (Exception ex)
+ {
+ count = 0;
+ }
+ finally
+ {
+ if (br != null) br.close();
+ if (is != null) is.close();
+ }
+
+ return count;
+ }
}
\ No newline at end of file
diff --git a/framework/src/main/java/org/apache/felix/framework/cache/BundleCache.java b/framework/src/main/java/org/apache/felix/framework/cache/BundleCache.java
index 92a5be0..04358d1 100644
--- a/framework/src/main/java/org/apache/felix/framework/cache/BundleCache.java
+++ b/framework/src/main/java/org/apache/felix/framework/cache/BundleCache.java
@@ -154,7 +154,7 @@
archiveList.toArray(new BundleArchive[archiveList.size()]);
}
- public BundleArchive create(long id, String location, InputStream is)
+ public BundleArchive create(long id, String location, int startLevel, InputStream is)
throws Exception
{
File cacheDir = determineCacheDir(m_configMap);
@@ -167,7 +167,8 @@
{
// Create the archive and add it to the list of archives.
BundleArchive ba =
- new BundleArchive(m_logger, m_configMap, archiveRootDir, id, location, is);
+ new BundleArchive(
+ m_logger, m_configMap, archiveRootDir, id, location, startLevel, is);
return ba;
}
catch (Exception ex)