michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: package org.mozilla.gecko.background.healthreport.prune; michael@0: michael@0: import org.mozilla.gecko.background.common.log.Logger; michael@0: import org.mozilla.gecko.background.healthreport.Environment; michael@0: import org.mozilla.gecko.background.healthreport.EnvironmentBuilder; michael@0: import org.mozilla.gecko.background.healthreport.HealthReportDatabaseStorage; michael@0: import org.mozilla.gecko.background.healthreport.ProfileInformationCache; michael@0: michael@0: import android.content.ContentProviderClient; michael@0: import android.content.Context; michael@0: michael@0: /** michael@0: * Abstracts over the Storage instance behind the PrunePolicy. The underlying storage instance is michael@0: * a {@link HealthReportDatabaseStorage} instance. Since our cleanup routine vacuums, auto_vacuum michael@0: * can be disabled. It is enabled by default, however, turning it off requires an expensive vacuum michael@0: * so we wait until our first {@link cleanup} call since we are vacuuming anyway. michael@0: */ michael@0: public class PrunePolicyDatabaseStorage implements PrunePolicyStorage { michael@0: public static final String LOG_TAG = PrunePolicyDatabaseStorage.class.getSimpleName(); michael@0: michael@0: private final Context context; michael@0: private final String profilePath; michael@0: michael@0: private ContentProviderClient client; michael@0: private HealthReportDatabaseStorage storage; michael@0: michael@0: private int currentEnvironmentID; // So we don't prune the current environment. michael@0: michael@0: public PrunePolicyDatabaseStorage(final Context context, final String profilePath) { michael@0: this.context = context; michael@0: this.profilePath = profilePath; michael@0: michael@0: this.currentEnvironmentID = -1; michael@0: } michael@0: michael@0: public void pruneEvents(final int count) { michael@0: getStorage().pruneEvents(count); michael@0: } michael@0: michael@0: public void pruneEnvironments(final int count) { michael@0: getStorage().pruneEnvironments(count); michael@0: michael@0: // Re-populate the DB and environment cache with the current environment in the unlikely event michael@0: // that it was deleted. michael@0: this.currentEnvironmentID = -1; michael@0: getCurrentEnvironmentID(); michael@0: } michael@0: michael@0: /** michael@0: * Deletes data recorded before the given time. Note that if this method fails to retrieve the michael@0: * current environment from the profile cache, it will not delete data so be sure to prune by michael@0: * other methods (e.g. {@link pruneEvents}) as well. michael@0: */ michael@0: public int deleteDataBefore(final long time) { michael@0: return getStorage().deleteDataBefore(time, getCurrentEnvironmentID()); michael@0: } michael@0: michael@0: public void cleanup() { michael@0: final HealthReportDatabaseStorage storage = getStorage(); michael@0: // The change to auto_vacuum will only take affect after a vacuum. michael@0: storage.disableAutoVacuuming(); michael@0: storage.vacuum(); michael@0: } michael@0: michael@0: public int getEventCount() { michael@0: return getStorage().getEventCount(); michael@0: } michael@0: michael@0: public int getEnvironmentCount() { michael@0: return getStorage().getEnvironmentCount(); michael@0: } michael@0: michael@0: public void close() { michael@0: if (client != null) { michael@0: client.release(); michael@0: client = null; michael@0: } michael@0: } michael@0: michael@0: /** michael@0: * Retrieves the {@link HealthReportDatabaseStorage} associated with the profile of the policy. michael@0: * For efficiency, the underlying {@link ContentProviderClient} and michael@0: * {@link HealthReportDatabaseStorage} are cached for later invocations. However, this means a michael@0: * call to this method MUST be accompanied by a call to {@link close}. Throws michael@0: * {@link IllegalStateException} if the storage instance could not be retrieved - note that the michael@0: * {@link ContentProviderClient} instance will not be closed in this case and michael@0: * {@link releaseClient} should still be called. michael@0: */ michael@0: protected HealthReportDatabaseStorage getStorage() { michael@0: if (storage != null) { michael@0: return storage; michael@0: } michael@0: michael@0: client = EnvironmentBuilder.getContentProviderClient(context); michael@0: if (client == null) { michael@0: // TODO: Record prune failures and submit as part of FHR upload. michael@0: Logger.warn(LOG_TAG, "Unable to get ContentProviderClient - throwing."); michael@0: throw new IllegalStateException("Unable to get ContentProviderClient."); michael@0: } michael@0: michael@0: try { michael@0: storage = EnvironmentBuilder.getStorage(client, profilePath); michael@0: if (storage == null) { michael@0: // TODO: Record prune failures and submit as part of FHR upload. michael@0: Logger.warn(LOG_TAG,"Unable to get HealthReportDatabaseStorage for " + profilePath + michael@0: " - throwing."); michael@0: throw new IllegalStateException("Unable to get HealthReportDatabaseStorage for " + michael@0: profilePath + " (== null)."); michael@0: } michael@0: } catch (ClassCastException ex) { michael@0: // TODO: Record prune failures and submit as part of FHR upload. michael@0: Logger.warn(LOG_TAG,"Unable to get HealthReportDatabaseStorage for " + profilePath + michael@0: profilePath + " (ClassCastException)."); michael@0: throw new IllegalStateException("Unable to get HealthReportDatabaseStorage for " + michael@0: profilePath + ".", ex); michael@0: } michael@0: michael@0: return storage; michael@0: } michael@0: michael@0: protected int getCurrentEnvironmentID() { michael@0: if (currentEnvironmentID < 0) { michael@0: final ProfileInformationCache cache = new ProfileInformationCache(profilePath); michael@0: if (!cache.restoreUnlessInitialized()) { michael@0: throw new IllegalStateException("Current environment unknown."); michael@0: } michael@0: final Environment env = EnvironmentBuilder.getCurrentEnvironment(cache); michael@0: currentEnvironmentID = env.register(); michael@0: } michael@0: return currentEnvironmentID; michael@0: } michael@0: }