-
Notifications
You must be signed in to change notification settings - Fork 614
Canonical ID Schema Migration #1182
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -49,7 +49,7 @@ class SQLiteSchema { | |
* The version of the schema. Increase this by one for each migration added to runMigrations | ||
* below. | ||
*/ | ||
static final int VERSION = 10; | ||
static final int VERSION = 11; | ||
|
||
// Remove this constant and increment VERSION to enable indexing support | ||
static final int INDEXING_SUPPORT_VERSION = VERSION + 1; | ||
|
@@ -65,9 +65,11 @@ class SQLiteSchema { | |
|
||
private final SQLiteDatabase db; | ||
|
||
// PORTING NOTE: The Android client doesn't need to use a serializer to remove held write acks. | ||
SQLiteSchema(SQLiteDatabase db) { | ||
private final LocalSerializer serializer; | ||
|
||
SQLiteSchema(SQLiteDatabase db, LocalSerializer serializer) { | ||
this.db = db; | ||
this.serializer = serializer; | ||
} | ||
|
||
void runMigrations() { | ||
|
@@ -151,6 +153,11 @@ void runMigrations(int fromVersion, int toVersion) { | |
dropLastLimboFreeSnapshotVersion(); | ||
} | ||
|
||
if (fromVersion < 11 && toVersion >= 11) { | ||
// Schema version 11 changed the format of canonical IDs in the target cache. | ||
rewriteCanonicalIds(); | ||
} | ||
|
||
/* | ||
* Adding a new migration? READ THIS FIRST! | ||
* | ||
|
@@ -530,6 +537,26 @@ List<String> getTableColumns(String table) { | |
return columns; | ||
} | ||
|
||
private void rewriteCanonicalIds() { | ||
new SQLitePersistence.Query(db, "SELECT target_id, target_proto FROM targets") | ||
.forEach( | ||
cursor -> { | ||
int targetId = cursor.getInt(0); | ||
byte[] targetProtoBytes = cursor.getBlob(1); | ||
|
||
try { | ||
Target targetProto = Target.parseFrom(targetProtoBytes); | ||
TargetData targetData = serializer.decodeTargetData(targetProto); | ||
String updatedCanonicalId = targetData.getTarget().getCanonicalId(); | ||
db.execSQL( | ||
"UPDATE targets SET canonical_id = ? WHERE target_id = ?", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This migration can't be rolled back and has the potential to cause problems because If a user does roll back, will this actually cause a problem with duplicate target ids? I think probably not because the next target id is in target_globals and we're not changing that here, right? One alternative that makes this slightly more rollback friendly would be to put the new target id in a new column and create an additional index on that column. I can't say I'm super excited about this prospect and likely would prefer to just document that this release includes a migration that can't be rolled-back from. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good catch. The fix for this is actually pretty straightforward as we can always rewrite canonical IDs with the current format. The target IDs don't change and as as long the format in the schema matches the expected format at the current client version we should be safe. I modified the schema converter to support downgrades and updated the code to run this particular migration on both up- and downgrades. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hm. I just realized that the new version of the schema converter is pretty dumb. It assumes that my shiny new code is shipped to old SDKs. What do you think about submitting the PR in its original form and letting LRU GC delete stale QueryData if the user chooses to downgrade? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Letting LRU GC do its thing SGTM. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I reverted the commit that pretended to add support for downgrades. |
||
new Object[] {updatedCanonicalId, targetId}); | ||
} catch (InvalidProtocolBufferException e) { | ||
throw fail("Failed to decode Query data for target %s", targetId); | ||
} | ||
}); | ||
}; | ||
|
||
private boolean tableExists(String table) { | ||
return !new SQLitePersistence.Query(db, "SELECT 1=1 FROM sqlite_master WHERE tbl_name = ?") | ||
.binding(table) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Dumb question: this file doesn't appear to employ a transaction anywhere. Doesn't
db.execSQL
auto-commit if you don't? It seems like it would be bad if this partially committed.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The transaction is opened here: https://cs.corp.google.com/aosp-master/frameworks/base/core/java/android/database/sqlite/SQLiteOpenHelper.java?q=f:SQLiteopenhelper.java&dr&l=409
It will only get committed if line 421 executes.