Wrap database update in an explicit transaction

All changes to the database in SQLite must be done within a
transaction, so if there isn't one in progress one will be started
implicitly, i.e. each change will be done in a separate transaction.

Since committing a transaction is a fairly expensive operation - on
some filesystems ridiculously expensive - it should be done as
sparingly as possible.

In tests on my Galaxy S, this change makes the update between 2500%
and 4500% faster (for slightly over 100 applications).
This commit is contained in:
Henrik Tunedal 2011-02-14 01:32:13 +01:00
parent 0d1be2d967
commit 657ae58418
2 changed files with 19 additions and 4 deletions

View File

@ -491,6 +491,10 @@ public class DB {
updateApps = getApps(null, null, true); updateApps = getApps(null, null, true);
Log.d("FDroid", "AppUpdate: " + updateApps.size() Log.d("FDroid", "AppUpdate: " + updateApps.size()
+ " apps before starting."); + " apps before starting.");
// Wrap the whole update in a transaction. Make sure to call
// either endUpdate or cancelUpdate to commit or discard it,
// respectively.
db.beginTransaction();
} }
// Called when a repo update ends. Any applications that have not been // Called when a repo update ends. Any applications that have not been
@ -521,12 +525,20 @@ public class DB {
} }
} }
} }
// Commit updates to the database.
db.setTransactionSuccessful();
db.endTransaction();
Log.d("FDroid", "AppUpdate: " + updateApps.size() Log.d("FDroid", "AppUpdate: " + updateApps.size()
+ " apps on completion."); + " apps on completion.");
updateApps = null; updateApps = null;
return; return;
} }
// Called instead of endUpdate if the update failed.
public void cancelUpdate() {
db.endTransaction();
}
// Called during update to supply new details for an application (or // Called during update to supply new details for an application (or
// details of a completely new one). Calls to this must be wrapped by // details of a completely new one). Calls to this must be wrapped by
// a call to beginUpdate and a call to endUpdate. // a call to beginUpdate and a call to endUpdate.

View File

@ -223,6 +223,7 @@ public class RepoXMLHandler extends DefaultHandler {
public static boolean doUpdates(Context ctx, DB db) { public static boolean doUpdates(Context ctx, DB db) {
long startTime = System.currentTimeMillis(); long startTime = System.currentTimeMillis();
boolean success = true;
db.beginUpdate(); db.beginUpdate();
Vector<DB.Repo> repos = db.getRepos(); Vector<DB.Repo> repos = db.getRepos();
for (DB.Repo repo : repos) { for (DB.Repo repo : repos) {
@ -262,12 +263,12 @@ public class RepoXMLHandler extends DefaultHandler {
jar.close(); jar.close();
if (certs == null) { if (certs == null) {
Log.d("FDroid", "No signature found in index"); Log.d("FDroid", "No signature found in index");
return false; return success = false;
} }
if (certs.length != 1) { if (certs.length != 1) {
Log.d("FDroid", "Expected one signature - found " Log.d("FDroid", "Expected one signature - found "
+ certs.length); + certs.length);
return false; return success = false;
} }
byte[] sig = certs[0].getEncoded(); byte[] sig = certs[0].getEncoded();
@ -285,7 +286,7 @@ public class RepoXMLHandler extends DefaultHandler {
if (!ssig.equals(repo.pubkey)) { if (!ssig.equals(repo.pubkey)) {
Log.d("FDroid", "Index signature mismatch"); Log.d("FDroid", "Index signature mismatch");
return false; return success = false;
} }
} else { } else {
@ -324,10 +325,12 @@ public class RepoXMLHandler extends DefaultHandler {
} catch (Exception e) { } catch (Exception e) {
Log.e("FDroid", "Exception updating from " + repo.address Log.e("FDroid", "Exception updating from " + repo.address
+ ":\n" + Log.getStackTraceString(e)); + ":\n" + Log.getStackTraceString(e));
return false; return success = false;
} finally { } finally {
ctx.deleteFile("tempindex.xml"); ctx.deleteFile("tempindex.xml");
ctx.deleteFile("tempindex.jar"); ctx.deleteFile("tempindex.jar");
if (!success)
db.cancelUpdate();
} }
} }