|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 |
|
5 package org.mozilla.gecko.background.healthreport.prune; |
|
6 |
|
7 import org.mozilla.gecko.background.common.log.Logger; |
|
8 import org.mozilla.gecko.background.healthreport.Environment; |
|
9 import org.mozilla.gecko.background.healthreport.EnvironmentBuilder; |
|
10 import org.mozilla.gecko.background.healthreport.HealthReportDatabaseStorage; |
|
11 import org.mozilla.gecko.background.healthreport.ProfileInformationCache; |
|
12 |
|
13 import android.content.ContentProviderClient; |
|
14 import android.content.Context; |
|
15 |
|
16 /** |
|
17 * Abstracts over the Storage instance behind the PrunePolicy. The underlying storage instance is |
|
18 * a {@link HealthReportDatabaseStorage} instance. Since our cleanup routine vacuums, auto_vacuum |
|
19 * can be disabled. It is enabled by default, however, turning it off requires an expensive vacuum |
|
20 * so we wait until our first {@link cleanup} call since we are vacuuming anyway. |
|
21 */ |
|
22 public class PrunePolicyDatabaseStorage implements PrunePolicyStorage { |
|
23 public static final String LOG_TAG = PrunePolicyDatabaseStorage.class.getSimpleName(); |
|
24 |
|
25 private final Context context; |
|
26 private final String profilePath; |
|
27 |
|
28 private ContentProviderClient client; |
|
29 private HealthReportDatabaseStorage storage; |
|
30 |
|
31 private int currentEnvironmentID; // So we don't prune the current environment. |
|
32 |
|
33 public PrunePolicyDatabaseStorage(final Context context, final String profilePath) { |
|
34 this.context = context; |
|
35 this.profilePath = profilePath; |
|
36 |
|
37 this.currentEnvironmentID = -1; |
|
38 } |
|
39 |
|
40 public void pruneEvents(final int count) { |
|
41 getStorage().pruneEvents(count); |
|
42 } |
|
43 |
|
44 public void pruneEnvironments(final int count) { |
|
45 getStorage().pruneEnvironments(count); |
|
46 |
|
47 // Re-populate the DB and environment cache with the current environment in the unlikely event |
|
48 // that it was deleted. |
|
49 this.currentEnvironmentID = -1; |
|
50 getCurrentEnvironmentID(); |
|
51 } |
|
52 |
|
53 /** |
|
54 * Deletes data recorded before the given time. Note that if this method fails to retrieve the |
|
55 * current environment from the profile cache, it will not delete data so be sure to prune by |
|
56 * other methods (e.g. {@link pruneEvents}) as well. |
|
57 */ |
|
58 public int deleteDataBefore(final long time) { |
|
59 return getStorage().deleteDataBefore(time, getCurrentEnvironmentID()); |
|
60 } |
|
61 |
|
62 public void cleanup() { |
|
63 final HealthReportDatabaseStorage storage = getStorage(); |
|
64 // The change to auto_vacuum will only take affect after a vacuum. |
|
65 storage.disableAutoVacuuming(); |
|
66 storage.vacuum(); |
|
67 } |
|
68 |
|
69 public int getEventCount() { |
|
70 return getStorage().getEventCount(); |
|
71 } |
|
72 |
|
73 public int getEnvironmentCount() { |
|
74 return getStorage().getEnvironmentCount(); |
|
75 } |
|
76 |
|
77 public void close() { |
|
78 if (client != null) { |
|
79 client.release(); |
|
80 client = null; |
|
81 } |
|
82 } |
|
83 |
|
84 /** |
|
85 * Retrieves the {@link HealthReportDatabaseStorage} associated with the profile of the policy. |
|
86 * For efficiency, the underlying {@link ContentProviderClient} and |
|
87 * {@link HealthReportDatabaseStorage} are cached for later invocations. However, this means a |
|
88 * call to this method MUST be accompanied by a call to {@link close}. Throws |
|
89 * {@link IllegalStateException} if the storage instance could not be retrieved - note that the |
|
90 * {@link ContentProviderClient} instance will not be closed in this case and |
|
91 * {@link releaseClient} should still be called. |
|
92 */ |
|
93 protected HealthReportDatabaseStorage getStorage() { |
|
94 if (storage != null) { |
|
95 return storage; |
|
96 } |
|
97 |
|
98 client = EnvironmentBuilder.getContentProviderClient(context); |
|
99 if (client == null) { |
|
100 // TODO: Record prune failures and submit as part of FHR upload. |
|
101 Logger.warn(LOG_TAG, "Unable to get ContentProviderClient - throwing."); |
|
102 throw new IllegalStateException("Unable to get ContentProviderClient."); |
|
103 } |
|
104 |
|
105 try { |
|
106 storage = EnvironmentBuilder.getStorage(client, profilePath); |
|
107 if (storage == null) { |
|
108 // TODO: Record prune failures and submit as part of FHR upload. |
|
109 Logger.warn(LOG_TAG,"Unable to get HealthReportDatabaseStorage for " + profilePath + |
|
110 " - throwing."); |
|
111 throw new IllegalStateException("Unable to get HealthReportDatabaseStorage for " + |
|
112 profilePath + " (== null)."); |
|
113 } |
|
114 } catch (ClassCastException ex) { |
|
115 // TODO: Record prune failures and submit as part of FHR upload. |
|
116 Logger.warn(LOG_TAG,"Unable to get HealthReportDatabaseStorage for " + profilePath + |
|
117 profilePath + " (ClassCastException)."); |
|
118 throw new IllegalStateException("Unable to get HealthReportDatabaseStorage for " + |
|
119 profilePath + ".", ex); |
|
120 } |
|
121 |
|
122 return storage; |
|
123 } |
|
124 |
|
125 protected int getCurrentEnvironmentID() { |
|
126 if (currentEnvironmentID < 0) { |
|
127 final ProfileInformationCache cache = new ProfileInformationCache(profilePath); |
|
128 if (!cache.restoreUnlessInitialized()) { |
|
129 throw new IllegalStateException("Current environment unknown."); |
|
130 } |
|
131 final Environment env = EnvironmentBuilder.getCurrentEnvironment(cache); |
|
132 currentEnvironmentID = env.register(); |
|
133 } |
|
134 return currentEnvironmentID; |
|
135 } |
|
136 } |