allow adjustable cache cleanup

This commit is contained in:
dosiecki 2018-01-31 15:42:03 -08:00
parent 46172fba28
commit 3fdac7eb10
7 changed files with 72 additions and 32 deletions

View file

@ -236,6 +236,26 @@
</string-array>
<string name="default_network_select_value">NOMONONME</string>
<string name="menu_cache_age_select">Maximum Cache Age</string>
<string name="menu_cache_age_select_sum">Clean up cached story content after…</string>
<string name="menu_cache_age_select_opt_2d">2 days</string>
<string name="menu_cache_age_select_opt_7d">7 days</string>
<string name="menu_cache_age_select_opt_14d">14 days</string>
<string name="menu_cache_age_select_opt_30d">30 days</string>
<string-array name="cache_age_select_entries">
<item>@string/menu_cache_age_select_opt_2d</item>
<item>@string/menu_cache_age_select_opt_7d</item>
<item>@string/menu_cache_age_select_opt_14d</item>
<item>@string/menu_cache_age_select_opt_30d</item>
</string-array>
<string-array name="cache_age_select_values">
<item>CACHE_AGE_2D</item>
<item>CACHE_AGE_7D</item>
<item>CACHE_AGE_14D</item>
<item>CACHE_AGE_30D</item>
</string-array>
<string name="default_cache_age_select_value">CACHE_AGE_30D</string>
<string name="settings_cat_feed_list">Feed List</string>
<string name="settings_enable_row_global_shared">Show Global Shared Stories</string>

View file

@ -26,6 +26,14 @@
android:key="keep_old_stories"
android:title="@string/settings_keep_old_stories"
android:summary="@string/settings_keep_old_stories_sum" />
<ListPreference
android:key="cache_age_select"
android:title="@string/menu_cache_age_select"
android:dialogTitle="@string/menu_cache_age_select"
android:summary="@string/menu_cache_age_select_sum"
android:entries="@array/cache_age_select_entries"
android:entryValues="@array/cache_age_select_values"
android:defaultValue="@string/default_cache_age_select_value" />
</PreferenceCategory>
<PreferenceCategory

View file

@ -3,6 +3,7 @@ package com.newsblur.service;
import android.util.Log;
import com.newsblur.util.FileCache;
import com.newsblur.util.PrefConstants;
import com.newsblur.util.PrefsUtils;
public class CleanupService extends SubService {
@ -15,8 +16,6 @@ public class CleanupService extends SubService {
@Override
protected void exec() {
if (!PrefsUtils.isTimeToCleanup(parent)) return;
gotWork();
com.newsblur.util.Log.d(this.getClass().getName(), "cleaning up old stories");
@ -33,17 +32,15 @@ public class CleanupService extends SubService {
com.newsblur.util.Log.d(this.getClass().getName(), "cleaning up story image cache");
FileCache imageCache = FileCache.asStoryImageCache(parent);
imageCache.cleanupUnusedOrOld(parent.dbHelper.getAllStoryImages());
imageCache.cleanupUnusedAndOld(parent.dbHelper.getAllStoryImages(), PrefsUtils.getMaxCachedAgeMillis(parent));
com.newsblur.util.Log.d(this.getClass().getName(), "cleaning up icon cache");
FileCache iconCache = FileCache.asIconCache(parent);
iconCache.cleanupOld();
iconCache.cleanupOld(PrefConstants.CACHE_AGE_VALUE_30D);
com.newsblur.util.Log.d(this.getClass().getName(), "cleaning up thumbnail cache");
FileCache thumbCache = FileCache.asThumbnailCache(parent);
thumbCache.cleanupUnusedOrOld(parent.dbHelper.getAllStoryThumbnails());
PrefsUtils.updateLastCleanupTime(parent);
thumbCache.cleanupUnusedAndOld(parent.dbHelper.getAllStoryThumbnails(), PrefsUtils.getMaxCachedAgeMillis(parent));
}
public static boolean running() {

View file

@ -34,9 +34,6 @@ public class AppConstants {
// how often to rebuild the DB
public static final long VACUUM_TIME_MILLIS = 12L * 60L * 60L * 1000L;
// how often to clean up the DB
public static final long CLEANUP_TIME_MILLIS = 3L * 60L * 60L * 1000L;
// how often to trigger the BG service. slightly longer than how often we will find new stories,
// to account for the fact that it is approximate, and missing a cycle is bad.
public static final long BG_SERVICE_CYCLE_MILLIS = AUTO_SYNC_TIME_MILLIS + 30L * 1000L;

View file

@ -15,13 +15,11 @@ public class FileCache {
private static final long MIN_FREE_SPACE_BYTES = 250L * 1024L * 1024L;
private static final Pattern POSTFIX_PATTERN = Pattern.compile("(\\.[a-zA-Z0-9]+)[^\\.]*$");
private final long maxFileAgeMillis;
private final int minValidCacheBytes;
private final File cacheDir;
private FileCache(Context context, String subdir, long maxFileAgeMillis, int minValidCacheBytes) {
this.maxFileAgeMillis = maxFileAgeMillis;
private FileCache(Context context, String subdir, int minValidCacheBytes) {
this.minValidCacheBytes = minValidCacheBytes;
cacheDir = new File(context.getCacheDir(), subdir);
if (!cacheDir.exists()) {
@ -30,17 +28,17 @@ public class FileCache {
}
public static FileCache asStoryImageCache(Context context) {
FileCache fc = new FileCache(context, "olimages", 30L * 24L * 60L * 60L * 1000L, 512);
FileCache fc = new FileCache(context, "olimages", 512);
return fc;
}
public static FileCache asIconCache(Context context) {
FileCache fc = new FileCache(context, "icons", 45L * 24L * 60L * 60L * 1000L, 128);
FileCache fc = new FileCache(context, "icons", 128);
return fc;
}
public static FileCache asThumbnailCache(Context context) {
FileCache fc = new FileCache(context, "thumbs", 15L * 24L * 60L * 60L * 1000L, 256);
FileCache fc = new FileCache(context, "thumbs", 256);
return fc;
}
@ -109,22 +107,29 @@ public class FileCache {
return fileName;
}
public void cleanupOld() {
public void cleanupOld(long maxFileAgeMillis) {
try {
int cleaned = 0;
File[] files = cacheDir.listFiles();
if (files == null) return;
com.newsblur.util.Log.i(this, String.format( "have %d files", files.length));
for (File f : files) {
long timestamp = f.lastModified();
if (System.currentTimeMillis() > (timestamp + maxFileAgeMillis)) {
f.delete();
cleaned++;
}
}
com.newsblur.util.Log.i(this, String.format( "cleaned up %d files", cleaned));
} catch (Exception e) {
android.util.Log.e(FileCache.class.getName(), "exception cleaning up cache", e);
com.newsblur.util.Log.e(this, "exception cleaning up cache", e);
}
}
public void cleanupUnusedOrOld(Set<String> currentUrls) {
/**
* Clean up files in this cache that are both unused and past the specified age.
*/
public void cleanupUnusedAndOld(Set<String> currentUrls, long maxFileAgeMillis) {
// if there appear to be zero images in the system, a DB rebuild probably just
// occured, so don't trust that data for cleanup
if (currentUrls.size() == 0) return;
@ -132,17 +137,21 @@ public class FileCache {
Set<String> currentFiles = new HashSet<String>(currentUrls.size());
for (String url : currentUrls) currentFiles.add(getFileName(url));
try {
int cleaned = 0;
File[] files = cacheDir.listFiles();
if (files == null) return;
com.newsblur.util.Log.i(this, String.format( "have %d files", files.length));
for (File f : files) {
long timestamp = f.lastModified();
if ((System.currentTimeMillis() > (timestamp + maxFileAgeMillis)) ||
if ((System.currentTimeMillis() > (timestamp + maxFileAgeMillis)) &&
(!currentFiles.contains(f.getName()))) {
f.delete();
cleaned++;
}
}
com.newsblur.util.Log.i(this, String.format( "cleaned up %d files", cleaned));
} catch (Exception e) {
android.util.Log.e(FileCache.class.getName(), "exception cleaning up cache", e);
com.newsblur.util.Log.e(this, "exception cleaning up cache", e);
}
}

View file

@ -62,11 +62,21 @@ public class PrefConstants {
public static final String ENABLE_IMAGE_PREFETCH = "enable_image_prefetch";
public static final String NETWORK_SELECT = "offline_network_select";
public static final String KEEP_OLD_STORIES = "keep_old_stories";
public static final String CACHE_AGE_SELECT = "cache_age_select";
public static final String NETWORK_SELECT_ANY = "ANY";
public static final String NETWORK_SELECT_NOMO = "NOMO";
public static final String NETWORK_SELECT_NOMONONME = "NOMONONME";
public static final String CACHE_AGE_SELECT_2D = "CACHE_AGE_2D";
public static final String CACHE_AGE_SELECT_7D = "CACHE_AGE_7D";
public static final String CACHE_AGE_SELECT_14D = "CACHE_AGE_14D";
public static final String CACHE_AGE_SELECT_30D = "CACHE_AGE_30D";
public static final long CACHE_AGE_VALUE_2D = 1000L * 60L * 60L * 24L * 2L;
public static final long CACHE_AGE_VALUE_7D = 1000L * 60L * 60L * 24L * 7L;
public static final long CACHE_AGE_VALUE_14D = 1000L * 60L * 60L * 24L * 14L;
public static final long CACHE_AGE_VALUE_30D = 1000L * 60L * 60L * 24L * 30L;
public static final String ENABLE_ROW_GLOBAL_SHARED = "enable_row_global_shared";
public static final String ENABLE_ROW_INFREQUENT_STORIES = "enable_row_infrequent_stories";

View file

@ -318,17 +318,6 @@ public class PrefsUtils {
prefs.edit().putLong(PrefConstants.LAST_VACUUM_TIME, (new Date()).getTime()).commit();
}
public static boolean isTimeToCleanup(Context context) {
SharedPreferences prefs = context.getSharedPreferences(PrefConstants.PREFERENCES, 0);
long lastTime = prefs.getLong(PrefConstants.LAST_CLEANUP_TIME, 1L);
return ( (lastTime + AppConstants.CLEANUP_TIME_MILLIS) < (new Date()).getTime() );
}
public static void updateLastCleanupTime(Context context) {
SharedPreferences prefs = context.getSharedPreferences(PrefConstants.PREFERENCES, 0);
prefs.edit().putLong(PrefConstants.LAST_CLEANUP_TIME, (new Date()).getTime()).commit();
}
public static StoryOrder getStoryOrderForFeed(Context context, String feedId) {
SharedPreferences prefs = context.getSharedPreferences(PrefConstants.PREFERENCES, 0);
return StoryOrder.valueOf(prefs.getString(PrefConstants.FEED_STORY_ORDER_PREFIX + feedId, getDefaultStoryOrder(prefs).toString()));
@ -660,6 +649,16 @@ public class PrefsUtils {
return prefs.getBoolean(PrefConstants.KEEP_OLD_STORIES, false);
}
public static long getMaxCachedAgeMillis(Context context) {
SharedPreferences prefs = context.getSharedPreferences(PrefConstants.PREFERENCES, 0);
String val = prefs.getString(PrefConstants.CACHE_AGE_SELECT, PrefConstants.CACHE_AGE_SELECT_30D);
if (val.equals(PrefConstants.CACHE_AGE_SELECT_2D)) return PrefConstants.CACHE_AGE_VALUE_2D;
if (val.equals(PrefConstants.CACHE_AGE_SELECT_7D)) return PrefConstants.CACHE_AGE_VALUE_7D;
if (val.equals(PrefConstants.CACHE_AGE_SELECT_14D)) return PrefConstants.CACHE_AGE_VALUE_14D;
if (val.equals(PrefConstants.CACHE_AGE_SELECT_30D)) return PrefConstants.CACHE_AGE_VALUE_30D;
return PrefConstants.CACHE_AGE_VALUE_30D;
}
public static void applyThemePreference(Activity activity) {
ThemeValue value = getSelectedTheme(activity);
if (value == ThemeValue.LIGHT) {