Skip to content

Commit ed6348d

Browse files
Canonical ID Schema Migration
1 parent 9354294 commit ed6348d

File tree

3 files changed

+82
-11
lines changed

3 files changed

+82
-11
lines changed

firebase-firestore/src/main/java/com/google/firebase/firestore/local/SQLitePersistence.java

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,10 @@ public SQLitePersistence(
108108
DatabaseId databaseId,
109109
LocalSerializer serializer,
110110
LruGarbageCollector.Params params) {
111-
this(serializer, params, new OpenHelper(context, databaseName(persistenceKey, databaseId)));
111+
this(
112+
serializer,
113+
params,
114+
new OpenHelper(context, serializer, databaseName(persistenceKey, databaseId)));
112115
}
113116

114117
public SQLitePersistence(
@@ -274,10 +277,12 @@ private long getPageCount() {
274277
*/
275278
private static class OpenHelper extends SQLiteOpenHelper {
276279

280+
private final LocalSerializer serializer;
277281
private boolean configured;
278282

279-
OpenHelper(Context context, String databaseName) {
283+
OpenHelper(Context context, LocalSerializer serializer, String databaseName) {
280284
super(context, databaseName, null, SQLiteSchema.VERSION);
285+
this.serializer = serializer;
281286
}
282287

283288
@Override
@@ -303,13 +308,13 @@ private void ensureConfigured(SQLiteDatabase db) {
303308
@Override
304309
public void onCreate(SQLiteDatabase db) {
305310
ensureConfigured(db);
306-
new SQLiteSchema(db).runMigrations(0);
311+
new SQLiteSchema(db, serializer).runMigrations(0);
307312
}
308313

309314
@Override
310315
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
311316
ensureConfigured(db);
312-
new SQLiteSchema(db).runMigrations(oldVersion);
317+
new SQLiteSchema(db, serializer).runMigrations(oldVersion);
313318
}
314319

315320
@Override

firebase-firestore/src/main/java/com/google/firebase/firestore/local/SQLiteSchema.java

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ class SQLiteSchema {
4949
* The version of the schema. Increase this by one for each migration added to runMigrations
5050
* below.
5151
*/
52-
static final int VERSION = 10;
52+
static final int VERSION = 11;
5353

5454
// Remove this constant and increment VERSION to enable indexing support
5555
static final int INDEXING_SUPPORT_VERSION = VERSION + 1;
@@ -65,9 +65,11 @@ class SQLiteSchema {
6565

6666
private final SQLiteDatabase db;
6767

68-
// PORTING NOTE: The Android client doesn't need to use a serializer to remove held write acks.
69-
SQLiteSchema(SQLiteDatabase db) {
68+
private final LocalSerializer serializer;
69+
70+
SQLiteSchema(SQLiteDatabase db, LocalSerializer serializer) {
7071
this.db = db;
72+
this.serializer = serializer;
7173
}
7274

7375
void runMigrations() {
@@ -151,6 +153,11 @@ void runMigrations(int fromVersion, int toVersion) {
151153
dropLastLimboFreeSnapshotVersion();
152154
}
153155

156+
if (fromVersion < 11 && toVersion >= 11) {
157+
// Schema version 11 changed the format of canonical IDs in the target cache.
158+
rewriteCanonicalIds();
159+
}
160+
154161
/*
155162
* Adding a new migration? READ THIS FIRST!
156163
*
@@ -530,6 +537,26 @@ List<String> getTableColumns(String table) {
530537
return columns;
531538
}
532539

540+
private void rewriteCanonicalIds() {
541+
new SQLitePersistence.Query(db, "SELECT target_id, target_proto FROM targets")
542+
.forEach(
543+
cursor -> {
544+
int targetId = cursor.getInt(0);
545+
byte[] targetProtoBytes = cursor.getBlob(1);
546+
547+
try {
548+
Target targetProto = Target.parseFrom(targetProtoBytes);
549+
TargetData targetData = serializer.decodeTargetData(targetProto);
550+
String updatedCanonicalId = targetData.getTarget().getCanonicalId();
551+
db.execSQL(
552+
"UPDATE targets SET canonical_id = ? WHERE target_id = ?",
553+
new Object[] {updatedCanonicalId, targetId});
554+
} catch (InvalidProtocolBufferException e) {
555+
throw fail("Failed to decode Query data for target %s", targetId);
556+
}
557+
});
558+
};
559+
533560
private boolean tableExists(String table) {
534561
return !new SQLitePersistence.Query(db, "SELECT 1=1 FROM sqlite_master WHERE tbl_name = ?")
535562
.binding(table)

firebase-firestore/src/test/java/com/google/firebase/firestore/local/SQLiteSchemaTest.java

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
import static com.google.firebase.firestore.local.EncodedPath.decodeResourcePath;
1818
import static com.google.firebase.firestore.local.EncodedPath.encode;
19+
import static com.google.firebase.firestore.testutil.TestUtil.filter;
1920
import static com.google.firebase.firestore.testutil.TestUtil.key;
2021
import static com.google.firebase.firestore.testutil.TestUtil.map;
2122
import static com.google.firebase.firestore.testutil.TestUtil.path;
@@ -33,6 +34,7 @@
3334
import android.database.sqlite.SQLiteOpenHelper;
3435
import androidx.test.core.app.ApplicationProvider;
3536
import com.google.firebase.database.collection.ImmutableSortedMap;
37+
import com.google.firebase.firestore.core.Query;
3638
import com.google.firebase.firestore.model.DatabaseId;
3739
import com.google.firebase.firestore.model.DocumentKey;
3840
import com.google.firebase.firestore.model.ResourcePath;
@@ -68,8 +70,13 @@ public class SQLiteSchemaTest {
6870
private SQLiteSchema schema;
6971
private SQLiteOpenHelper opener;
7072

73+
private DatabaseId databaseId;
74+
private LocalSerializer serializer;
75+
7176
@Before
7277
public void setUp() {
78+
databaseId = DatabaseId.forProject("foo");
79+
serializer = new LocalSerializer(new RemoteSerializer(databaseId));
7380
opener =
7481
new SQLiteOpenHelper(ApplicationProvider.getApplicationContext(), "foo", null, 1) {
7582
@Override
@@ -79,7 +86,7 @@ public void onCreate(SQLiteDatabase db) {}
7986
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {}
8087
};
8188
db = opener.getWritableDatabase();
82-
schema = new SQLiteSchema(db);
89+
schema = new SQLiteSchema(db, serializer);
8390
}
8491

8592
@After
@@ -521,14 +528,46 @@ public void keepsLastLimboFreeSnapshotIfNotDowngraded() {
521528
Target targetProto = Target.parseFrom(targetProtoBytes);
522529
assertTrue(targetProto.hasLastLimboFreeSnapshotVersion());
523530
} catch (InvalidProtocolBufferException e) {
524-
fail("Failed to decode Query data");
531+
fail("Failed to decode Target data");
532+
}
533+
});
534+
}
535+
536+
@Test
537+
public void rewritesCanonicalIds() {
538+
schema.runMigrations(0, 10);
539+
540+
Query filteredQuery = query("colletion").filter(filter("foo", "==", "bar"));
541+
TargetData initialTargetData =
542+
new TargetData(
543+
filteredQuery.toTarget(),
544+
/* targetId= */ 2,
545+
/* sequenceNumber= */ 1,
546+
QueryPurpose.LISTEN);
547+
548+
db.execSQL(
549+
"INSERT INTO targets (target_id, canonical_id, target_proto) VALUES (?,?, ?)",
550+
new Object[] {2, "foo", serializer.encodeTargetData(initialTargetData).toByteArray()});
551+
552+
schema.runMigrations(10, 11);
553+
new SQLitePersistence.Query(db, "SELECT canonical_id, target_proto, canonical_id FROM targets")
554+
.forEach(
555+
cursor -> {
556+
String actualCanonicalId = cursor.getString(0);
557+
byte[] targetProtoBytes = cursor.getBlob(1);
558+
559+
try {
560+
Target targetProto = Target.parseFrom(targetProtoBytes);
561+
TargetData targetData = serializer.decodeTargetData(targetProto);
562+
String expectedCanonicalId = targetData.getTarget().getCanonicalId();
563+
assertEquals(actualCanonicalId, expectedCanonicalId);
564+
} catch (InvalidProtocolBufferException e) {
565+
fail("Failed to decode Target data");
525566
}
526567
});
527568
}
528569

529570
private SQLiteRemoteDocumentCache createRemoteDocumentCache() {
530-
DatabaseId databaseId = DatabaseId.forProject("foo");
531-
LocalSerializer serializer = new LocalSerializer(new RemoteSerializer(databaseId));
532571
SQLitePersistence persistence =
533572
new SQLitePersistence(serializer, LruGarbageCollector.Params.Default(), opener);
534573
persistence.start();

0 commit comments

Comments
 (0)