Skip to content

Commit b34278d

Browse files
authored
Merge pull request #1402 from couchbase/feature/issue_888
Fixed https://github.com/couchbase/couchbase-lite-android/issues/888
2 parents 9bc2313 + de5d8b2 commit b34278d

1 file changed

Lines changed: 75 additions & 14 deletions

File tree

src/main/java/com/couchbase/lite/Manager.java

Lines changed: 75 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -795,7 +795,8 @@ public boolean accept(File file, String name) {
795795
String filename = file.getName();
796796
String name = nameOfDatabaseAtPath(filename);
797797
String oldDbPath = new File(directory, filename).getAbsolutePath();
798-
upgradeDatabase(name, oldDbPath, true);
798+
if (!upgradeDatabase(name, oldDbPath, true))
799+
throw new RuntimeException("Database upgrade failed for: " + name);
799800
}
800801
}
801802

@@ -804,28 +805,88 @@ public boolean accept(File file, String name) {
804805
* - (BOOL) upgradeDatabaseNamed: (NSString*)name
805806
* atPath: (NSString*)dbPath
806807
* error: (NSError**)outError
808+
*
809+
* NOTE: upgradeDatabase() method is called if the old database exists.
807810
*/
808811
private boolean upgradeDatabase(String name, String dbPath, boolean close) {
809-
Log.v(Log.TAG_DATABASE, "CouchbaseLite: Upgrading database at %s ...", dbPath);
810-
if (!name.equals("_replicator")) {
811-
// Create and open new CBLDatabase:
812-
Database db = getDatabase(name, false);
813-
if (db == null) {
814-
Log.w(Log.TAG_DATABASE, "Upgrade failed: Creating new db failed");
812+
Log.v(Log.TAG_DATABASE, "CouchbaseLite: Upgrading database (%s) at %s ...", name, dbPath);
813+
814+
// if db with name already exists, not need to migrate. Simply remove old database
815+
Database db = getDatabase(name, false);
816+
if (!db.exists() && !name.equals("_replicator")) {
817+
818+
// temporary database name for new db schema
819+
String tempName = name + ".tmp";
820+
821+
// Create and open new CBLDatabase with temporary name:
822+
Database tmpDB = getDatabase(tempName, false);
823+
if (tmpDB == null) {
824+
Log.w(Log.TAG_DATABASE,
825+
"Upgrade failed: Creating new db failed: %s", tempName);
815826
return false;
816827
}
817-
if (!db.exists()) {
818-
// Upgrade the old database into the new one:
819-
DatabaseUpgrade upgrader = new DatabaseUpgrade(this, db, dbPath);
820-
if (!upgrader.importData()) {
821-
upgrader.backOut();
828+
829+
// upgradeDatabase() is called only if dbPath (old db version) exists. So presence of
830+
// temporary db indicates that previous upgrade crashed midway.
831+
if (tmpDB.exists()) {
832+
Log.v(Log.TAG_DATABASE, "Previous upgrade probably crashed midway. dbPath: " + dbPath);
833+
834+
// rollback from temporary database to old database
835+
// NOTE: Deleting temporary db is not enough because `DatabaseUpgrade.importData()`
836+
// move attachment files instead of copy files.
837+
DatabaseUpgrade upgrader = new DatabaseUpgrade(this, tmpDB, dbPath);
838+
upgrader.backOut();
839+
840+
// temporary db is deleted by previous operation, reopen the temporary db.
841+
tmpDB = getDatabase(tempName, false);
842+
if (tmpDB == null) {
843+
Log.w(Log.TAG_DATABASE, "Upgrade failed: Creating new db failed: %s", tempName);
822844
return false;
823845
}
824846
}
825-
if (close)
826-
db.close();
847+
848+
if (tmpDB.exists()) {
849+
// the temporary db should not exist. Just double check
850+
Log.w(Log.TAG_DATABASE,
851+
"Upgrade failed: Failed to delete already existing db: %s", tempName);
852+
return false;
853+
}
854+
855+
// Upgrade the old database into the new one:
856+
DatabaseUpgrade upgrader = new DatabaseUpgrade(this, tmpDB, dbPath);
857+
if (!upgrader.importData()) {
858+
upgrader.backOut();
859+
return false;
860+
}
861+
862+
// close temporary database
863+
tmpDB.close();
864+
865+
// rename temporary database name to new name
866+
File tmpPath = new File(pathForDatabaseNamed(tempName));
867+
File newPath = new File(pathForDatabaseNamed(name));
868+
if (!tmpPath.renameTo(newPath)) {
869+
Log.w(Log.TAG_DATABASE,
870+
"Upgrade failed: Failed to rename db folder from temporary name: %s -> %s",
871+
tmpPath, newPath);
872+
upgrader = new DatabaseUpgrade(this, getDatabase(tempName, false), dbPath);
873+
upgrader.backOut();
874+
return false;
875+
}
876+
877+
// reopen db with name
878+
db = getDatabase(name, false);
879+
if (!db.exists()) {
880+
Log.w(Log.TAG_DATABASE,
881+
"Upgrade failed: Failed to open the database after migrate: %s", name);
882+
return false;
883+
}
827884
}
828885

886+
// close db if necessary
887+
if (close)
888+
db.close();
889+
829890
// Remove old database file and its SQLite side files:
830891
moveSQLiteDbFiles(dbPath, null);
831892

0 commit comments

Comments
 (0)