Bug 1133763 - Part 3: Wipe out the cache directory when detecting a change in the DB schema; r=bkelly

This commit is contained in:
Ehsan Akhgari 2015-03-04 17:05:37 -05:00
parent 58b1ce9c4b
commit d5840b488d
6 changed files with 70 additions and 6 deletions

View File

@ -14,6 +14,8 @@
#include "nsIFile.h"
#include "nsIURI.h"
#include "nsNetUtil.h"
#include "DBSchema.h"
#include "FileUtils.h"
namespace mozilla {
namespace dom {
@ -75,6 +77,8 @@ DBAction::OpenConnection(const QuotaInfo& aQuotaInfo, nsIFile* aDBDir,
MOZ_ASSERT(aDBDir);
MOZ_ASSERT(aConnOut);
nsCOMPtr<mozIStorageConnection> conn;
bool exists;
nsresult rv = aDBDir->Exists(&exists);
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
@ -123,21 +127,48 @@ DBAction::OpenConnection(const QuotaInfo& aQuotaInfo, nsIFile* aDBDir,
do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID);
if (NS_WARN_IF(!ss)) { return NS_ERROR_UNEXPECTED; }
rv = ss->OpenDatabaseWithFileURL(dbFileUrl, aConnOut);
rv = ss->OpenDatabaseWithFileURL(dbFileUrl, getter_AddRefs(conn));
if (rv == NS_ERROR_FILE_CORRUPTED) {
NS_WARNING("Cache database corrupted. Recreating empty database.");
conn = nullptr;
// There is nothing else we can do to recover. Also, this data can
// be deleted by QuotaManager at any time anyways.
rv = dbFile->Remove(false);
rv = WipeDatabase(dbFile, aDBDir);
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
// TODO: clean up any orphaned body files (bug 1110446)
rv = ss->OpenDatabaseWithFileURL(dbFileUrl, aConnOut);
rv = ss->OpenDatabaseWithFileURL(dbFileUrl, getter_AddRefs(conn));
}
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
MOZ_ASSERT(*aConnOut);
// Check the schema to make sure it is not too old.
int32_t schemaVersion = 0;
rv = conn->GetSchemaVersion(&schemaVersion);
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
if (schemaVersion > 0 && schemaVersion < DBSchema::kMaxWipeSchemaVersion) {
conn = nullptr;
rv = WipeDatabase(dbFile, aDBDir);
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
rv = ss->OpenDatabaseWithFileURL(dbFileUrl, getter_AddRefs(conn));
}
conn.forget(aConnOut);
return rv;
}
nsresult
DBAction::WipeDatabase(nsIFile* aDBFile, nsIFile* aDBDir)
{
nsresult rv = aDBFile->Remove(false);
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
// Delete the morgue as well.
rv = FileUtils::BodyDeleteDir(aDBDir);
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
return rv;
}

View File

@ -49,6 +49,8 @@ private:
nsresult OpenConnection(const QuotaInfo& aQuotaInfo, nsIFile* aQuotaDir,
mozIStorageConnection** aConnOut);
nsresult WipeDatabase(nsIFile* aDBFile, nsIFile* aDBDir);
const Mode mMode;
};

View File

@ -20,6 +20,7 @@ namespace dom {
namespace cache {
const int32_t DBSchema::kMaxWipeSchemaVersion = 1;
const int32_t DBSchema::kLatestSchemaVersion = 1;
const int32_t DBSchema::kMaxEntriesPerStatement = 255;

View File

@ -88,6 +88,9 @@ public:
Namespace aNamespace,
nsTArray<nsString>& aKeysOut);
// We will wipe out databases with a schema versions less than this.
static const int32_t kMaxWipeSchemaVersion;
private:
typedef int32_t EntryId;

View File

@ -47,6 +47,29 @@ FileUtils::BodyCreateDir(nsIFile* aBaseDir)
return rv;
}
// static
nsresult
FileUtils::BodyDeleteDir(nsIFile* aBaseDir)
{
MOZ_ASSERT(aBaseDir);
nsCOMPtr<nsIFile> aBodyDir;
nsresult rv = aBaseDir->Clone(getter_AddRefs(aBodyDir));
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
rv = aBodyDir->Append(NS_LITERAL_STRING("morgue"));
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
rv = aBodyDir->Remove(/* recursive = */ true);
if (rv == NS_ERROR_FILE_NOT_FOUND ||
rv == NS_ERROR_FILE_TARGET_DOES_NOT_EXIST) {
rv = NS_OK;
}
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
return rv;
}
// static
nsresult
FileUtils::BodyGetCacheDir(nsIFile* aBaseDir, const nsID& aId,

View File

@ -30,6 +30,10 @@ public:
};
static nsresult BodyCreateDir(nsIFile* aBaseDir);
// Note that this function can only be used during the initialization of the
// database. We're unlikely to be able to delete the DB successfully past
// that point due to the file being in use.
static nsresult BodyDeleteDir(nsIFile* aBaseDir);
static nsresult BodyGetCacheDir(nsIFile* aBaseDir, const nsID& aId,
nsIFile** aCacheDirOut);