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.
This commit is contained in:
Peter Serwylo 2017-07-17 12:45:16 +10:00
parent e26748e0e0
commit 1bd9a73dbc
2 changed files with 32 additions and 1 deletions

View File

@ -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;
/**

View File

@ -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<String, Long> 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);