From 1bd9a73dbc563b0ec042ef5487cda8cba16d1401 Mon Sep 17 00:00:00 2001 From: Peter Serwylo Date: Mon, 17 Jul 2017 12:45:16 +1000 Subject: [PATCH] Cache results of category-id query. Each app insert required asking the database for the ID of each category an app is in. Given the categories don't change (ever) but are only appended to, we can cache the results in a static Java variable for increased performance. This reduced the "repo persister" logic for me from 50 seconds for main F-Droid and 100 seconds for Archive, down to 15 seconds and 30 seconds respectively. --- .../org/fdroid/fdroid/data/AppProvider.java | 2 ++ .../fdroid/fdroid/data/CategoryProvider.java | 31 ++++++++++++++++++- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/org/fdroid/fdroid/data/AppProvider.java b/app/src/main/java/org/fdroid/fdroid/data/AppProvider.java index 36426fc0d..4b7f74c1b 100644 --- a/app/src/main/java/org/fdroid/fdroid/data/AppProvider.java +++ b/app/src/main/java/org/fdroid/fdroid/data/AppProvider.java @@ -24,8 +24,10 @@ import org.fdroid.fdroid.data.Schema.RepoTable; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; /** diff --git a/app/src/main/java/org/fdroid/fdroid/data/CategoryProvider.java b/app/src/main/java/org/fdroid/fdroid/data/CategoryProvider.java index 6810fdd48..3997d43dd 100644 --- a/app/src/main/java/org/fdroid/fdroid/data/CategoryProvider.java +++ b/app/src/main/java/org/fdroid/fdroid/data/CategoryProvider.java @@ -12,13 +12,39 @@ import org.fdroid.fdroid.data.Schema.CategoryTable; import org.fdroid.fdroid.data.Schema.CategoryTable.Cols; import org.fdroid.fdroid.data.Schema.PackageTable; +import java.util.HashMap; +import java.util.Map; + public class CategoryProvider extends FDroidProvider { public static final class Helper { private Helper() { } + /** + * During repo updates, each app needs to know the ID of each category it belongs to. + * This results in lots of database lookups, usually at least one for each app, sometimes more. + * To improve performance, this caches the association between categories and their database IDs. + * + * It can stay around for the entire F-Droid process, even across multiple repo updates, as we + * don't actually remove data from the categories table. + */ + private static final Map KNOWN_CATEGORIES = new HashMap<>(); + + /** + * Used by tests to clear that the "Category -> ID" cache (used to prevent excessive disk reads). + */ + static void clearCategoryIdCache() { + KNOWN_CATEGORIES.clear(); + } + public static long ensureExists(Context context, String category) { + // Check our in-memory cache to potentially prevent a trip to the database (and hence disk). + String lowerCaseCategory = category.toLowerCase(); + if (KNOWN_CATEGORIES.containsKey(lowerCaseCategory)) { + return KNOWN_CATEGORIES.get(lowerCaseCategory); + } + long id = getCategoryId(context, category); if (id <= 0) { ContentValues values = new ContentValues(1); @@ -26,10 +52,13 @@ public class CategoryProvider extends FDroidProvider { Uri uri = context.getContentResolver().insert(getContentUri(), values); id = Long.parseLong(uri.getLastPathSegment()); } + + KNOWN_CATEGORIES.put(lowerCaseCategory, id); + return id; } - public static long getCategoryId(Context context, String category) { + private static long getCategoryId(Context context, String category) { String[] projection = new String[]{Cols.ROW_ID}; Cursor cursor = context.getContentResolver().query(getCategoryUri(category), projection, null, null, null);