Use temporary, in memory database for update process.
This increases the speed of the complex queries required at the end of the update process to: * calculate suggested version codes * figure out icon urls * etc, by two orders of magnitude.
This commit is contained in:
parent
ab248525e0
commit
721dcb00c1
@ -91,9 +91,8 @@ public class RepoPersister {
|
|||||||
// end of the process. This is due to the fact that we can't verify the cert
|
// end of the process. This is due to the fact that we can't verify the cert
|
||||||
// the index was signed with until we've finished reading it - and we don't
|
// the index was signed with until we've finished reading it - and we don't
|
||||||
// want to put stuff in the real database until we are sure it is from a
|
// want to put stuff in the real database until we are sure it is from a
|
||||||
// trusted source.
|
// trusted source. It also helps performance as it is done via an in-memory database.
|
||||||
TempAppProvider.Helper.init(context);
|
TempAppProvider.Helper.init(context);
|
||||||
TempApkProvider.Helper.init(context);
|
|
||||||
hasBeenInitialized = true;
|
hasBeenInitialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,12 +68,16 @@ public class TempApkProvider extends ApkProvider {
|
|||||||
/**
|
/**
|
||||||
* Deletes the old temporary table (if it exists). Then creates a new temporary apk provider
|
* Deletes the old temporary table (if it exists). Then creates a new temporary apk provider
|
||||||
* table and populates it with all the data from the real apk provider table.
|
* table and populates it with all the data from the real apk provider table.
|
||||||
|
*
|
||||||
|
* This is package local because it must be invoked after
|
||||||
|
* {@link org.fdroid.fdroid.data.TempAppProvider.Helper#init(Context)}. Due to this
|
||||||
|
* dependence, that method invokes this one itself, rather than leaving it to the
|
||||||
|
* {@link RepoPersister}.
|
||||||
*/
|
*/
|
||||||
public static void init(Context context) {
|
static void init(Context context) {
|
||||||
Uri uri = Uri.withAppendedPath(getContentUri(), PATH_INIT);
|
Uri uri = Uri.withAppendedPath(getContentUri(), PATH_INIT);
|
||||||
context.getContentResolver().insert(uri, new ContentValues());
|
context.getContentResolver().insert(uri, new ContentValues());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -123,11 +127,11 @@ public class TempApkProvider extends ApkProvider {
|
|||||||
|
|
||||||
private void initTable() {
|
private void initTable() {
|
||||||
final SQLiteDatabase db = db();
|
final SQLiteDatabase db = db();
|
||||||
db.execSQL("DROP TABLE IF EXISTS " + getTableName());
|
final String memoryDbName = TempAppProvider.DB;
|
||||||
db.execSQL("CREATE TABLE " + getTableName() + " AS SELECT * FROM " + DBHelper.TABLE_APK);
|
db.execSQL("CREATE TABLE " + memoryDbName + "." + getTableName() + " AS SELECT * FROM main." + DBHelper.TABLE_APK);
|
||||||
db.execSQL("CREATE INDEX IF NOT EXISTS apk_vercode on " + getTableName() + " (vercode);");
|
db.execSQL("CREATE INDEX IF NOT EXISTS " + memoryDbName + ".apk_vercode on " + getTableName() + " (vercode);");
|
||||||
db.execSQL("CREATE INDEX IF NOT EXISTS apk_id on " + getTableName() + " (id);");
|
db.execSQL("CREATE INDEX IF NOT EXISTS " + memoryDbName + ".apk_id on " + getTableName() + " (id);");
|
||||||
db.execSQL("CREATE INDEX IF NOT EXISTS apk_compatible ON " + getTableName() + " (compatible);");
|
db.execSQL("CREATE INDEX IF NOT EXISTS " + memoryDbName + ".apk_compatible ON " + getTableName() + " (compatible);");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -3,8 +3,10 @@ package org.fdroid.fdroid.data;
|
|||||||
import android.content.ContentValues;
|
import android.content.ContentValues;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.UriMatcher;
|
import android.content.UriMatcher;
|
||||||
|
import android.database.Cursor;
|
||||||
import android.database.sqlite.SQLiteDatabase;
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import android.text.TextUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import org.fdroid.fdroid.Utils;
|
import org.fdroid.fdroid.Utils;
|
||||||
@ -16,6 +18,11 @@ public class TempAppProvider extends AppProvider {
|
|||||||
|
|
||||||
private static final String TAG = "TempAppProvider";
|
private static final String TAG = "TempAppProvider";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the in memory database used for updating.
|
||||||
|
*/
|
||||||
|
static final String DB = "temp_update_db";
|
||||||
|
|
||||||
private static final String PROVIDER_NAME = "TempAppProvider";
|
private static final String PROVIDER_NAME = "TempAppProvider";
|
||||||
|
|
||||||
private static final String TABLE_TEMP_APP = "temp_" + DBHelper.TABLE_APP;
|
private static final String TABLE_TEMP_APP = "temp_" + DBHelper.TABLE_APP;
|
||||||
@ -60,6 +67,7 @@ public class TempAppProvider extends AppProvider {
|
|||||||
public static void init(Context context) {
|
public static void init(Context context) {
|
||||||
Uri uri = Uri.withAppendedPath(getContentUri(), PATH_INIT);
|
Uri uri = Uri.withAppendedPath(getContentUri(), PATH_INIT);
|
||||||
context.getContentResolver().insert(uri, new ContentValues());
|
context.getContentResolver().insert(uri, new ContentValues());
|
||||||
|
TempApkProvider.Helper.init(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -111,13 +119,30 @@ public class TempAppProvider extends AppProvider {
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ensureTempTableDetached(SQLiteDatabase db) {
|
||||||
|
Cursor cursor = db.rawQuery("PRAGMA database_list", null);
|
||||||
|
try {
|
||||||
|
cursor.moveToFirst();
|
||||||
|
while (!cursor.isAfterLast()) {
|
||||||
|
String name = cursor.getString(cursor.getColumnIndex("name"));
|
||||||
|
if (TextUtils.equals(name, DB)) {
|
||||||
|
db.execSQL("DETACH DATABASE " + DB);
|
||||||
|
}
|
||||||
|
cursor.moveToNext();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void initTable() {
|
private void initTable() {
|
||||||
final SQLiteDatabase db = db();
|
final SQLiteDatabase db = db();
|
||||||
db.execSQL("DROP TABLE IF EXISTS " + getTableName());
|
ensureTempTableDetached(db);
|
||||||
db.execSQL("CREATE TABLE " + getTableName() + " AS SELECT * FROM " + DBHelper.TABLE_APP);
|
db.execSQL("ATTACH DATABASE ':memory:' AS " + DB);
|
||||||
db.execSQL("CREATE INDEX IF NOT EXISTS app_id ON " + getTableName() + " (id);");
|
db.execSQL("CREATE TABLE " + DB + "." + getTableName() + " AS SELECT * FROM main." + DBHelper.TABLE_APP);
|
||||||
db.execSQL("CREATE INDEX IF NOT EXISTS app_upstreamVercode ON " + getTableName() + " (upstreamVercode);");
|
db.execSQL("CREATE INDEX IF NOT EXISTS " + DB + ".app_id ON " + getTableName() + " (id);");
|
||||||
db.execSQL("CREATE INDEX IF NOT EXISTS app_compatible ON " + getTableName() + " (compatible);");
|
db.execSQL("CREATE INDEX IF NOT EXISTS " + DB + ".app_upstreamVercode ON " + getTableName() + " (upstreamVercode);");
|
||||||
|
db.execSQL("CREATE INDEX IF NOT EXISTS " + DB + ".app_compatible ON " + getTableName() + " (compatible);");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void commitTable() {
|
private void commitTable() {
|
||||||
@ -125,21 +150,22 @@ public class TempAppProvider extends AppProvider {
|
|||||||
try {
|
try {
|
||||||
db.beginTransaction();
|
db.beginTransaction();
|
||||||
|
|
||||||
Log.i(TAG, "Renaming " + TABLE_TEMP_APP + " to " + DBHelper.TABLE_APP);
|
final String tempApp = DB + "." + TempAppProvider.TABLE_TEMP_APP;
|
||||||
db.execSQL("DROP TABLE " + DBHelper.TABLE_APP);
|
final String tempApk = DB + "." + TempApkProvider.TABLE_TEMP_APK;
|
||||||
db.execSQL("ALTER TABLE " + TABLE_TEMP_APP + " RENAME TO " + DBHelper.TABLE_APP);
|
|
||||||
|
|
||||||
Log.i(TAG, "Renaming " + TempApkProvider.TABLE_TEMP_APK + " to " + DBHelper.TABLE_APK);
|
db.execSQL("DELETE FROM " + DBHelper.TABLE_APP + " WHERE 1");
|
||||||
db.execSQL("DROP TABLE " + DBHelper.TABLE_APK);
|
db.execSQL("INSERT INTO " + DBHelper.TABLE_APP + " SELECT * FROM " + tempApp);
|
||||||
db.execSQL("ALTER TABLE " + TempApkProvider.TABLE_TEMP_APK + " RENAME TO " + DBHelper.TABLE_APK);
|
|
||||||
|
db.execSQL("DELETE FROM " + DBHelper.TABLE_APK + " WHERE 1");
|
||||||
|
db.execSQL("INSERT INTO " + DBHelper.TABLE_APK + " SELECT * FROM " + tempApk);
|
||||||
|
|
||||||
Utils.debugLog(TAG, "Successfully renamed both tables, will commit transaction");
|
|
||||||
db.setTransactionSuccessful();
|
db.setTransactionSuccessful();
|
||||||
|
|
||||||
getContext().getContentResolver().notifyChange(AppProvider.getContentUri(), null);
|
getContext().getContentResolver().notifyChange(AppProvider.getContentUri(), null);
|
||||||
getContext().getContentResolver().notifyChange(ApkProvider.getContentUri(), null);
|
getContext().getContentResolver().notifyChange(ApkProvider.getContentUri(), null);
|
||||||
} finally {
|
} finally {
|
||||||
db.endTransaction();
|
db.endTransaction();
|
||||||
|
db.execSQL("DETACH DATABASE " + DB); // Can't be done in a transaction.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user