Bug 1686191 - Have a way to specifically report warnings around QM_TRY; r=asuth,sg,dom-storage-reviewers

This patch:
- adds QM_WARNONLY_TRY/QM_NOTEONLY_TRY macros
- adds QM_WARNONLY_TRY_UNWRAP/QM_NOTEONLY_TRY_UNWRAP macros
- adds QM_OR_ELSE_WARN/QM_OR_ELSE_NOTE sub macros
- replaces non-propagating uses of NS_WARNING with redundant messages by
  QM_WARNONLY_TRY
- replaces uses of QM_TRY with orElse by QM_TRY(QM_OR_ELSE_WARN(...))
- replaces uses of QM_TRY inside an extra lambda with QM_WARNONLY_TRY
- replaces uses of QM_TRY with QM_VOID with QM_WARNONLY_TRY.
- replaces uses of QM_TRY with unwanted warnings with QM_NOTEONLY_TRY
- replaces uses of QM_TRY with additional Maybe wrapping for doing a
  fallback with QM_TRY(QM_OR_ELSE_WARN(...))

Differential Revision: https://phabricator.services.mozilla.com/D108424
This commit is contained in:
Jan Varga 2021-03-24 04:40:10 +00:00
Родитель 1b4f665f90
Коммит 6edcf204fd
18 изменённых файлов: 975 добавлений и 567 удалений

6
dom/cache/CacheParent.cpp поставляемый
Просмотреть файл

@ -57,10 +57,8 @@ mozilla::ipc::IPCResult CacheParent::RecvPCacheOpConstructor(
} }
mozilla::ipc::IPCResult CacheParent::RecvTeardown() { mozilla::ipc::IPCResult CacheParent::RecvTeardown() {
if (!Send__delete__(this)) { // If child process is gone, warn and allow actor to clean up normally
// child process is gone, warn and allow actor to clean up normally QM_WARNONLY_TRY(OkIf(Send__delete__(this)));
NS_WARNING("Cache failed to send delete.");
}
return IPC_OK(); return IPC_OK();
} }

6
dom/cache/CacheStorageParent.cpp поставляемый
Просмотреть файл

@ -99,10 +99,8 @@ mozilla::ipc::IPCResult CacheStorageParent::RecvPCacheOpConstructor(
} }
mozilla::ipc::IPCResult CacheStorageParent::RecvTeardown() { mozilla::ipc::IPCResult CacheStorageParent::RecvTeardown() {
if (!Send__delete__(this)) { // If child process is gone, warn and allow actor to clean up normally
// child process is gone, warn and allow actor to clean up normally QM_WARNONLY_TRY(OkIf(Send__delete__(this)));
NS_WARNING("CacheStorage failed to delete actor.");
}
return IPC_OK(); return IPC_OK();
} }

8
dom/cache/CacheStreamControlParent.cpp поставляемый
Просмотреть файл

@ -145,11 +145,9 @@ void CacheStreamControlParent::CloseAll() {
void CacheStreamControlParent::Shutdown() { void CacheStreamControlParent::Shutdown() {
NS_ASSERT_OWNINGTHREAD(CacheStreamControlParent); NS_ASSERT_OWNINGTHREAD(CacheStreamControlParent);
if (!Send__delete__(this)) {
// child process is gone, allow actor to be destroyed normally // If child process is gone, warn and allow actor to clean up normally
NS_WARNING("Cache failed to delete stream actor."); QM_WARNONLY_TRY(OkIf(Send__delete__(this)));
return;
}
} }
void CacheStreamControlParent::NotifyCloseAll() { void CacheStreamControlParent::NotifyCloseAll() {

15
dom/cache/DBAction.cpp поставляемый
Просмотреть файл

@ -172,12 +172,13 @@ Result<nsCOMPtr<mozIStorageConnection>, nsresult> OpenDBConnection(
CACHE_TRY_UNWRAP( CACHE_TRY_UNWRAP(
auto conn, auto conn,
MOZ_TO_RESULT_INVOKE_TYPED(nsCOMPtr<mozIStorageConnection>, QM_OR_ELSE_WARN(
storageService, OpenDatabaseWithFileURL, MOZ_TO_RESULT_INVOKE_TYPED(nsCOMPtr<mozIStorageConnection>,
dbFileUrl, ""_ns) storageService, OpenDatabaseWithFileURL,
.orElse([&aQuotaInfo, &aDBFile, &storageService, dbFileUrl, ""_ns),
&dbFileUrl](const nsresult rv) ([&aQuotaInfo, &aDBFile, &storageService,
-> Result<nsCOMPtr<mozIStorageConnection>, nsresult> { &dbFileUrl](const nsresult rv)
-> Result<nsCOMPtr<mozIStorageConnection>, nsresult> {
if (IsDatabaseCorruptionError(rv)) { if (IsDatabaseCorruptionError(rv)) {
NS_WARNING( NS_WARNING(
"Cache database corrupted. Recreating empty database."); "Cache database corrupted. Recreating empty database.");
@ -191,7 +192,7 @@ Result<nsCOMPtr<mozIStorageConnection>, nsresult> OpenDBConnection(
OpenDatabaseWithFileURL, dbFileUrl, ""_ns)); OpenDatabaseWithFileURL, dbFileUrl, ""_ns));
} }
return Err(rv); return Err(rv);
})); })));
// Check the schema to make sure it is not too old. // Check the schema to make sure it is not too old.
CACHE_TRY_INSPECT(const int32_t& schemaVersion, CACHE_TRY_INSPECT(const int32_t& schemaVersion,

24
dom/cache/DBSchema.cpp поставляемый
Просмотреть файл

@ -421,16 +421,18 @@ class MOZ_RAII AutoDisableForeignKeyChecking {
MOZ_TO_RESULT_INVOKE(*state, GetInt32, 0), QM_VOID); MOZ_TO_RESULT_INVOKE(*state, GetInt32, 0), QM_VOID);
if (mode) { if (mode) {
CACHE_TRY(mConn->ExecuteSimpleSQL("PRAGMA foreign_keys = OFF;"_ns), QM_WARNONLY_TRY(
QM_VOID); ToResult(mConn->ExecuteSimpleSQL("PRAGMA foreign_keys = OFF;"_ns))
mForeignKeyCheckingDisabled = true; .andThen([this](const auto) -> Result<Ok, nsresult> {
mForeignKeyCheckingDisabled = true;
return Ok{};
}));
} }
} }
~AutoDisableForeignKeyChecking() { ~AutoDisableForeignKeyChecking() {
if (mForeignKeyCheckingDisabled) { if (mForeignKeyCheckingDisabled) {
CACHE_TRY(mConn->ExecuteSimpleSQL("PRAGMA foreign_keys = ON;"_ns), QM_WARNONLY_TRY(mConn->ExecuteSimpleSQL("PRAGMA foreign_keys = ON;"_ns));
QM_VOID);
} }
} }
@ -552,16 +554,8 @@ nsresult InitializeConnection(mozIStorageConnection& aConn) {
kPageSize))); kPageSize)));
// Limit fragmentation by growing the database by many pages at once. // Limit fragmentation by growing the database by many pages at once.
CACHE_TRY( QM_TRY(QM_OR_ELSE_WARN(ToResult(aConn.SetGrowthIncrement(kGrowthSize, ""_ns)),
ToResult(aConn.SetGrowthIncrement(kGrowthSize, ""_ns)) ErrToDefaultOkOrErr<NS_ERROR_FILE_TOO_BIG>));
.orElse([](const nsresult rv) -> Result<Ok, nsresult> {
if (rv == NS_ERROR_FILE_TOO_BIG) {
NS_WARNING(
"Not enough disk space to set sqlite growth increment.");
return Ok{};
}
return Err(rv);
}));
// Enable WAL journaling. This must be performed in a separate transaction // Enable WAL journaling. This must be performed in a separate transaction
// after changing the page_size and enabling auto_vacuum. // after changing the page_size and enabling auto_vacuum.

43
dom/cache/FileUtils.cpp поставляемый
Просмотреть файл

@ -89,8 +89,9 @@ Result<NotNull<nsCOMPtr<nsIFile>>, nsresult> BodyGetCacheDir(nsIFile& aBaseDir,
// the name of the sub-directory. // the name of the sub-directory.
CACHE_TRY(cacheDir->Append(IntToString(aId.m3[7]))); CACHE_TRY(cacheDir->Append(IntToString(aId.m3[7])));
CACHE_TRY(ToResult(cacheDir->Create(nsIFile::DIRECTORY_TYPE, 0755)) QM_TRY(
.orElse(ErrToDefaultOkOrErr<NS_ERROR_FILE_ALREADY_EXISTS, Ok>)); QM_OR_ELSE_WARN(ToResult(cacheDir->Create(nsIFile::DIRECTORY_TYPE, 0755)),
ErrToDefaultOkOrErr<NS_ERROR_FILE_ALREADY_EXISTS>));
return WrapNotNullUnchecked(std::move(cacheDir)); return WrapNotNullUnchecked(std::move(cacheDir));
} }
@ -101,8 +102,9 @@ nsresult BodyCreateDir(nsIFile& aBaseDir) {
CACHE_TRY_INSPECT(const auto& bodyDir, CACHE_TRY_INSPECT(const auto& bodyDir,
CloneFileAndAppend(aBaseDir, kMorgueDirectory)); CloneFileAndAppend(aBaseDir, kMorgueDirectory));
CACHE_TRY(ToResult(bodyDir->Create(nsIFile::DIRECTORY_TYPE, 0755)) QM_TRY(
.orElse(ErrToDefaultOkOrErr<NS_ERROR_FILE_ALREADY_EXISTS, Ok>)); QM_OR_ELSE_WARN(ToResult(bodyDir->Create(nsIFile::DIRECTORY_TYPE, 0755)),
ErrToDefaultOkOrErr<NS_ERROR_FILE_ALREADY_EXISTS>));
return NS_OK; return NS_OK;
} }
@ -163,7 +165,7 @@ Result<std::pair<nsID, nsCOMPtr<nsISupports>>, nsresult> BodyStartWriteStream(
} }
void BodyCancelWrite(nsISupports& aCopyContext) { void BodyCancelWrite(nsISupports& aCopyContext) {
CACHE_TRY(NS_CancelAsyncCopy(&aCopyContext, NS_ERROR_ABORT), QM_VOID); QM_WARNONLY_TRY(NS_CancelAsyncCopy(&aCopyContext, NS_ERROR_ABORT));
// TODO The partially written file must be cleaned up after the async copy // TODO The partially written file must be cleaned up after the async copy
// makes its callback. // makes its callback.
@ -432,8 +434,9 @@ Result<nsCOMPtr<nsIFile>, nsresult> GetMarkerFileHandle(
nsresult CreateMarkerFile(const QuotaInfo& aQuotaInfo) { nsresult CreateMarkerFile(const QuotaInfo& aQuotaInfo) {
CACHE_TRY_INSPECT(const auto& marker, GetMarkerFileHandle(aQuotaInfo)); CACHE_TRY_INSPECT(const auto& marker, GetMarkerFileHandle(aQuotaInfo));
CACHE_TRY(ToResult(marker->Create(nsIFile::NORMAL_FILE_TYPE, 0644)) QM_TRY(
.orElse(MapAlreadyExistsToDefault)); QM_OR_ELSE_WARN(ToResult(marker->Create(nsIFile::NORMAL_FILE_TYPE, 0644)),
MapAlreadyExistsToDefault));
// Note, we don't need to fsync here. We only care about actually // Note, we don't need to fsync here. We only care about actually
// writing the marker if later modifications to the Cache are // writing the marker if later modifications to the Cache are
@ -503,10 +506,11 @@ nsresult RemoveNsIFile(const QuotaInfo& aQuotaInfo, nsIFile& aFile,
const bool aTrackQuota) { const bool aTrackQuota) {
int64_t fileSize = 0; int64_t fileSize = 0;
if (aTrackQuota) { if (aTrackQuota) {
CACHE_TRY_INSPECT(const auto& maybeFileSize, CACHE_TRY_INSPECT(
MOZ_TO_RESULT_INVOKE(aFile, GetFileSize) const auto& maybeFileSize,
.map(Some<int64_t>) QM_OR_ELSE_WARN(
.orElse(MapNotFoundToDefault<Maybe<int64_t>>)); MOZ_TO_RESULT_INVOKE(aFile, GetFileSize).map(Some<int64_t>),
MapNotFoundToDefault<Maybe<int64_t>>));
if (!maybeFileSize) { if (!maybeFileSize) {
return NS_OK; return NS_OK;
@ -515,8 +519,8 @@ nsresult RemoveNsIFile(const QuotaInfo& aQuotaInfo, nsIFile& aFile,
fileSize = *maybeFileSize; fileSize = *maybeFileSize;
} }
CACHE_TRY(ToResult(aFile.Remove(/* recursive */ false)) QM_TRY(QM_OR_ELSE_WARN(ToResult(aFile.Remove(/* recursive */ false)),
.orElse(MapNotFoundToDefault<>)); MapNotFoundToDefault<>));
if (fileSize > 0) { if (fileSize > 0) {
MOZ_ASSERT(aTrackQuota); MOZ_ASSERT(aTrackQuota);
@ -587,10 +591,11 @@ nsresult LockedUpdateDirectoryPaddingFile(nsIFile& aBaseDir,
const auto directoryPaddingGetResult = const auto directoryPaddingGetResult =
aTemporaryFileExist ? Maybe<int64_t>{} : [&aBaseDir] { aTemporaryFileExist ? Maybe<int64_t>{} : [&aBaseDir] {
CACHE_TRY_RETURN(LockedDirectoryPaddingGet(aBaseDir) CACHE_TRY_RETURN(
.map(Some<int64_t>) QM_OR_ELSE_WARN(
.orElse(MapNotFoundToDefault<Maybe<int64_t>>), LockedDirectoryPaddingGet(aBaseDir).map(Some<int64_t>),
Maybe<int64_t>{}); MapNotFoundToDefault<Maybe<int64_t>>),
Maybe<int64_t>{});
}(); }();
CACHE_TRY_INSPECT( CACHE_TRY_INSPECT(
@ -708,8 +713,8 @@ nsresult LockedDirectoryPaddingDeleteFile(nsIFile& aBaseDir,
? nsLiteralString(PADDING_TMP_FILE_NAME) ? nsLiteralString(PADDING_TMP_FILE_NAME)
: nsLiteralString(PADDING_FILE_NAME))); : nsLiteralString(PADDING_FILE_NAME)));
CACHE_TRY(ToResult(file->Remove(/* recursive */ false)) QM_TRY(QM_OR_ELSE_WARN(ToResult(file->Remove(/* recursive */ false)),
.orElse(MapNotFoundToDefault<>)); MapNotFoundToDefault<>));
return NS_OK; return NS_OK;
} }

11
dom/cache/Manager.cpp поставляемый
Просмотреть файл

@ -140,13 +140,10 @@ class SetupAction final : public SyncDBAction {
// failure, but if we entered it and RestorePaddingFile succeeded, we // failure, but if we entered it and RestorePaddingFile succeeded, we
// would have returned NS_OK. Now, we will never propagate a // would have returned NS_OK. Now, we will never propagate a
// MaybeUpdatePaddingFile failure. // MaybeUpdatePaddingFile failure.
[&] { QM_WARNONLY_TRY(
CACHE_TRY(MaybeUpdatePaddingFile( MaybeUpdatePaddingFile(aDBDir, aConn, /* aIncreaceSize */ 0,
aDBDir, aConn, /* aIncreaceSize */ 0, overallDeletedPaddingSize.value(),
overallDeletedPaddingSize.value(), [&trans]() { return trans.Commit(); }));
[&trans]() mutable { return trans.Commit(); }),
QM_VOID);
}();
} }
if (DirectoryPaddingFileExists(*aDBDir, DirPaddingFile::TMP_FILE) || if (DirectoryPaddingFileExists(*aDBDir, DirPaddingFile::TMP_FILE) ||

8
dom/cache/PrincipalVerifier.cpp поставляемый
Просмотреть файл

@ -177,12 +177,8 @@ void PrincipalVerifier::DispatchToInitiatingThread(nsresult aRv) {
// This will result in a new CacheStorage object delaying operations until // This will result in a new CacheStorage object delaying operations until
// shutdown completes and the browser goes away. This is as graceful as // shutdown completes and the browser goes away. This is as graceful as
// we can get here. // we can get here.
nsresult rv = QM_WARNONLY_TRY(
mInitiatingEventTarget->Dispatch(this, nsIThread::DISPATCH_NORMAL); mInitiatingEventTarget->Dispatch(this, nsIThread::DISPATCH_NORMAL));
if (NS_FAILED(rv)) {
NS_WARNING(
"Cache unable to complete principal verification due to shutdown.");
}
} }
} // namespace mozilla::dom::cache } // namespace mozilla::dom::cache

31
dom/cache/QuotaClientImpl.h поставляемый
Просмотреть файл

@ -94,23 +94,24 @@ class CacheQuotaClient final : public quota::Client {
// the next action recalculate the padding size. // the next action recalculate the padding size.
CACHE_TRY(aCommitHook()); CACHE_TRY(aCommitHook());
CACHE_TRY( QM_TRY(QM_OR_ELSE_WARN(
ToResult(LockedDirectoryPaddingFinalizeWrite(aBaseDir)) ToResult(LockedDirectoryPaddingFinalizeWrite(aBaseDir)),
.orElse([&aBaseDir](const nsresult) -> Result<Ok, nsresult> { ([&aBaseDir](const nsresult) -> Result<Ok, nsresult> {
// Force restore file next time. // Force restore file next time.
Unused << LockedDirectoryPaddingDeleteFile( Unused << LockedDirectoryPaddingDeleteFile(aBaseDir,
aBaseDir, DirPaddingFile::FILE); DirPaddingFile::FILE);
// Ensure that we are able to force the padding file to be // Ensure that we are able to force the padding file to
// restored. // be restored.
MOZ_ASSERT(DirectoryPaddingFileExists( MOZ_ASSERT(
aBaseDir, DirPaddingFile::TMP_FILE)); DirectoryPaddingFileExists(aBaseDir, DirPaddingFile::TMP_FILE));
// Since both the body file and header have been stored in the // Since both the body file and header have been stored
// file-system, just make the action be resolve and let the // in the file-system, just make the action be resolve
// padding file be restored in the next action. // and let the padding file be restored in the next
return Ok{}; // action.
})); return Ok{};
})));
} }
return NS_OK; return NS_OK;

Просмотреть файл

@ -679,9 +679,9 @@ nsresult SetDefaultPragmas(mozIStorageConnection& aConnection) {
if (kSQLiteGrowthIncrement) { if (kSQLiteGrowthIncrement) {
// This is just an optimization so ignore the failure if the disk is // This is just an optimization so ignore the failure if the disk is
// currently too full. // currently too full.
IDB_TRY( IDB_TRY(QM_OR_ELSE_WARN(
ToResult(aConnection.SetGrowthIncrement(kSQLiteGrowthIncrement, ""_ns)) ToResult(aConnection.SetGrowthIncrement(kSQLiteGrowthIncrement, ""_ns)),
.orElse(ErrToDefaultOkOrErr<NS_ERROR_FILE_TOO_BIG, Ok>)); (ErrToDefaultOkOrErr<NS_ERROR_FILE_TOO_BIG, Ok>)));
} }
#endif // IDB_MOBILE #endif // IDB_MOBILE
@ -748,11 +748,12 @@ OpenDatabaseAndHandleBusy(mozIStorageService& aStorageService,
IDB_TRY_UNWRAP( IDB_TRY_UNWRAP(
auto connection, auto connection,
OpenDatabase(aStorageService, aFileURL, aTelemetryId) QM_OR_ELSE_WARN(
.map([](auto connection) -> ConnectionType { OpenDatabase(aStorageService, aFileURL, aTelemetryId)
return Some(std::move(connection)); .map([](auto connection) -> ConnectionType {
}) return Some(std::move(connection));
.orElse(ErrToDefaultOkOrErr<NS_ERROR_STORAGE_BUSY, ConnectionType>)); }),
(ErrToDefaultOkOrErr<NS_ERROR_STORAGE_BUSY, ConnectionType>)));
if (connection.isNothing()) { if (connection.isNothing()) {
#ifdef DEBUG #ifdef DEBUG
@ -777,12 +778,12 @@ OpenDatabaseAndHandleBusy(mozIStorageService& aStorageService,
IDB_TRY_UNWRAP( IDB_TRY_UNWRAP(
connection, connection,
OpenDatabase(aStorageService, aFileURL, aTelemetryId) QM_OR_ELSE_WARN(
.map([](auto connection) -> ConnectionType { OpenDatabase(aStorageService, aFileURL, aTelemetryId)
return Some(std::move(connection)); .map([](auto connection) -> ConnectionType {
}) return Some(std::move(connection));
.orElse([&start]( }),
nsresult aValue) -> Result<ConnectionType, nsresult> { ([&start](nsresult aValue) -> Result<ConnectionType, nsresult> {
if (aValue != NS_ERROR_STORAGE_BUSY || if (aValue != NS_ERROR_STORAGE_BUSY ||
TimeStamp::NowLoRes() - start > TimeStamp::NowLoRes() - start >
TimeDuration::FromSeconds(10)) { TimeDuration::FromSeconds(10)) {
@ -790,7 +791,7 @@ OpenDatabaseAndHandleBusy(mozIStorageService& aStorageService,
} }
return ConnectionType(); return ConnectionType();
})); })));
} while (connection.isNothing()); } while (connection.isNothing());
} }
@ -844,12 +845,13 @@ CreateStorageConnection(nsIFile& aDBFile, nsIFile& aFMDirectory,
IDB_TRY_UNWRAP( IDB_TRY_UNWRAP(
auto connection, auto connection,
OpenDatabaseAndHandleBusy(*storageService, *dbFileUrl, aTelemetryId) QM_OR_ELSE_WARN(
.map([](auto connection) -> nsCOMPtr<mozIStorageConnection> { OpenDatabaseAndHandleBusy(*storageService, *dbFileUrl, aTelemetryId)
return std::move(connection).unwrapBasePtr(); .map([](auto connection) -> nsCOMPtr<mozIStorageConnection> {
}) return std::move(connection).unwrapBasePtr();
.orElse([&aName](nsresult aValue) }),
-> Result<nsCOMPtr<mozIStorageConnection>, nsresult> { ([&aName](nsresult aValue)
-> Result<nsCOMPtr<mozIStorageConnection>, nsresult> {
// If we're just opening the database during origin initialization, // If we're just opening the database during origin initialization,
// then we don't want to erase any files. The failure here will fail // then we don't want to erase any files. The failure here will fail
// origin initialization too. // origin initialization too.
@ -858,7 +860,7 @@ CreateStorageConnection(nsIFile& aDBFile, nsIFile& aFMDirectory,
} }
return nsCOMPtr<mozIStorageConnection>(); return nsCOMPtr<mozIStorageConnection>();
})); })));
if (!connection) { if (!connection) {
// XXX Shouldn't we also update quota usage? // XXX Shouldn't we also update quota usage?
@ -5736,9 +5738,10 @@ nsresult DeleteFile(nsIFile& aFile, QuotaManager* const aQuotaManager,
if (aQuotaManager) { if (aQuotaManager) {
IDB_TRY_INSPECT( IDB_TRY_INSPECT(
const Maybe<int64_t>& fileSize, const Maybe<int64_t>& fileSize,
MOZ_TO_RESULT_INVOKE(aFile, GetFileSize) QM_OR_ELSE_WARN(
.map([](const int64_t val) { return Some(val); }) MOZ_TO_RESULT_INVOKE(aFile, GetFileSize)
.orElse(MakeMaybeIdempotentFilter<int64_t>(aIdempotent))); .map([](const int64_t val) { return Some(val); }),
MakeMaybeIdempotentFilter<int64_t>(aIdempotent)));
// XXX Can we really assert that the file size is not 0 if // XXX Can we really assert that the file size is not 0 if
// it existed? This might be violated by external // it existed? This might be violated by external
@ -5756,9 +5759,8 @@ nsresult DeleteFile(nsIFile& aFile, QuotaManager* const aQuotaManager,
} }
IDB_TRY_INSPECT(const auto& didExist, IDB_TRY_INSPECT(const auto& didExist,
ToResult(aFile.Remove(false)) QM_OR_ELSE_WARN(ToResult(aFile.Remove(false)).map(Some<Ok>),
.map(Some<Ok>) MakeMaybeIdempotentFilter<Ok>(aIdempotent)));
.orElse(MakeMaybeIdempotentFilter<Ok>(aIdempotent)));
if (!didExist) { if (!didExist) {
// XXX If we get here, this means that the file still existed when we // XXX If we get here, this means that the file still existed when we
@ -5804,9 +5806,9 @@ nsresult DeleteFilesNoQuota(nsIFile* aDirectory, const nsAString& aFilename) {
IDB_TRY_INSPECT(const auto& file, CloneFileAndAppend(*aDirectory, aFilename)); IDB_TRY_INSPECT(const auto& file, CloneFileAndAppend(*aDirectory, aFilename));
IDB_TRY_INSPECT( IDB_TRY_INSPECT(const auto& didExist,
const auto& didExist, QM_OR_ELSE_WARN(ToResult(file->Remove(true)).map(Some<Ok>),
ToResult(file->Remove(true)).map(Some<Ok>).orElse(IdempotentFilter<Ok>)); IdempotentFilter<Ok>));
Unused << didExist; Unused << didExist;
@ -5826,9 +5828,9 @@ Result<nsCOMPtr<nsIFile>, nsresult> CreateMarkerFile(
CloneFileAndAppend(aBaseDirectory, CloneFileAndAppend(aBaseDirectory,
kIdbDeletionMarkerFilePrefix + aDatabaseNameBase)); kIdbDeletionMarkerFilePrefix + aDatabaseNameBase));
IDB_TRY( QM_TRY(QM_OR_ELSE_WARN(
MOZ_TO_RESULT_INVOKE(markerFile, Create, nsIFile::NORMAL_FILE_TYPE, 0644) ToResult(markerFile->Create(nsIFile::NORMAL_FILE_TYPE, 0644)),
.orElse(ErrToDefaultOkOrErr<NS_ERROR_FILE_ALREADY_EXISTS, Ok>)); ErrToDefaultOkOrErr<NS_ERROR_FILE_ALREADY_EXISTS>));
return markerFile; return markerFile;
} }
@ -5860,27 +5862,27 @@ Result<Ok, nsresult> DeleteFileManagerDirectory(
uint64_t usageValue = fileUsage.GetValue().valueOr(0); uint64_t usageValue = fileUsage.GetValue().valueOr(0);
auto res = auto res = QM_OR_ELSE_WARN(
MOZ_TO_RESULT_INVOKE(aFileManagerDirectory, Remove, true) MOZ_TO_RESULT_INVOKE(aFileManagerDirectory, Remove, true),
.orElse([&usageValue, &aFileManagerDirectory](nsresult rv) { ([&usageValue, &aFileManagerDirectory](nsresult rv) {
// We may have deleted some files, try to update quota // We may have deleted some files, try to update quota
// information before returning the error. // information before returning the error.
// failures of GetUsage are intentionally ignored // failures of GetUsage are intentionally ignored
Unused << FileManager::GetUsage(&aFileManagerDirectory) Unused << FileManager::GetUsage(&aFileManagerDirectory)
.andThen([&usageValue](const auto& newFileUsage) { .andThen([&usageValue](const auto& newFileUsage) {
const auto newFileUsageValue = const auto newFileUsageValue =
newFileUsage.GetValue().valueOr(0); newFileUsage.GetValue().valueOr(0);
MOZ_ASSERT(newFileUsageValue <= usageValue); MOZ_ASSERT(newFileUsageValue <= usageValue);
usageValue -= newFileUsageValue; usageValue -= newFileUsageValue;
// XXX andThen does not support void return // XXX andThen does not support void return
// values right now, we must return a Result // values right now, we must return a Result
return Result<Ok, nsresult>{Ok{}}; return Result<Ok, nsresult>{Ok{}};
}); });
return Result<Ok, nsresult>{Err(rv)}; return Result<Ok, nsresult>{Err(rv)};
}); }));
if (usageValue) { if (usageValue) {
aQuotaManager->DecreaseUsageForClient( aQuotaManager->DecreaseUsageForClient(
@ -6775,11 +6777,8 @@ bool DeallocPBackgroundIndexedDBUtilsParent(
bool RecvFlushPendingFileDeletions() { bool RecvFlushPendingFileDeletions() {
AssertIsOnBackgroundThread(); AssertIsOnBackgroundThread();
QuotaClient* quotaClient = QuotaClient::GetInstance(); if (QuotaClient* quotaClient = QuotaClient::GetInstance()) {
if (quotaClient) { QM_WARNONLY_TRY(quotaClient->FlushPendingFileDeletions());
if (NS_FAILED(quotaClient->FlushPendingFileDeletions())) {
NS_WARNING("Failed to flush pending file deletions!");
}
} }
return true; return true;
@ -6891,29 +6890,30 @@ nsresult DatabaseConnection::BeginWriteTransaction() {
IDB_TRY_INSPECT(const auto& beginStmt, IDB_TRY_INSPECT(const auto& beginStmt,
BorrowCachedStatement("BEGIN IMMEDIATE;"_ns)); BorrowCachedStatement("BEGIN IMMEDIATE;"_ns));
IDB_TRY(ToResult(beginStmt->Execute()).orElse([&beginStmt](nsresult rv) { QM_TRY(QM_OR_ELSE_WARN(
if (rv == NS_ERROR_STORAGE_BUSY) { ToResult(beginStmt->Execute()), ([&beginStmt](nsresult rv) {
NS_WARNING( if (rv == NS_ERROR_STORAGE_BUSY) {
"Received NS_ERROR_STORAGE_BUSY when attempting to start write " NS_WARNING(
"transaction, retrying for up to 10 seconds"); "Received NS_ERROR_STORAGE_BUSY when attempting to start write "
"transaction, retrying for up to 10 seconds");
// Another thread must be using the database. Wait up to 10 seconds for // Another thread must be using the database. Wait up to 10 seconds
// that to complete. // for that to complete.
const TimeStamp start = TimeStamp::NowLoRes(); const TimeStamp start = TimeStamp::NowLoRes();
while (true) { while (true) {
PR_Sleep(PR_MillisecondsToInterval(100)); PR_Sleep(PR_MillisecondsToInterval(100));
rv = beginStmt->Execute(); rv = beginStmt->Execute();
if (rv != NS_ERROR_STORAGE_BUSY || if (rv != NS_ERROR_STORAGE_BUSY ||
TimeStamp::NowLoRes() - start > TimeDuration::FromSeconds(10)) { TimeStamp::NowLoRes() - start > TimeDuration::FromSeconds(10)) {
break; break;
}
}
} }
}
}
return Result<Ok, nsresult>{rv}; return Result<Ok, nsresult>{rv};
})); })));
mInWriteTransaction = true; mInWriteTransaction = true;
@ -6945,14 +6945,21 @@ void DatabaseConnection::RollbackWriteTransaction() {
return; return;
} }
IDB_TRY_INSPECT(const auto& stmt, BorrowCachedStatement("ROLLBACK;"_ns), QM_WARNONLY_TRY(
QM_VOID); BorrowCachedStatement("ROLLBACK;"_ns)
.andThen([&self = *this](const auto& stmt) -> Result<Ok, nsresult> {
// This may fail if SQLite already rolled back the transaction
// so ignore any errors.
// This may fail if SQLite already rolled back the transaction so ignore any // XXX ROLLBACK can fail quite normmally if a previous statement
// errors. // failed to execute successfully so SQLite rolled back the
Unused << stmt->Execute(); // transaction already. However, if it failed because of some other
// reason, we could try to close the connection.
Unused << stmt->Execute();
mInWriteTransaction = false; self.mInWriteTransaction = false;
return Ok{};
}));
} }
void DatabaseConnection::FinishWriteTransaction() { void DatabaseConnection::FinishWriteTransaction() {
@ -6967,9 +6974,11 @@ void DatabaseConnection::FinishWriteTransaction() {
mUpdateRefcountFunction->Reset(); mUpdateRefcountFunction->Reset();
} }
IDB_TRY(ExecuteCachedStatement("BEGIN;"_ns), QM_VOID); QM_WARNONLY_TRY(ToResult(ExecuteCachedStatement("BEGIN;"_ns))
.andThen([&](const auto) -> Result<Ok, nsresult> {
mInReadTransaction = true; mInReadTransaction = true;
return Ok{};
}));
} }
nsresult DatabaseConnection::StartSavepoint() { nsresult DatabaseConnection::StartSavepoint() {
@ -7120,18 +7129,17 @@ void DatabaseConnection::DoIdleProcessing(bool aNeedsCheckpoint) {
// Truncate the WAL if we were asked to or if we managed to free some space. // Truncate the WAL if we were asked to or if we managed to free some space.
if (aNeedsCheckpoint || freedSomePages) { if (aNeedsCheckpoint || freedSomePages) {
nsresult rv = CheckpointInternal(CheckpointMode::Truncate); QM_WARNONLY_TRY(CheckpointInternal(CheckpointMode::Truncate));
Unused << NS_WARN_IF(NS_FAILED(rv));
} }
// Finally try to restart the read transaction if we rolled it back earlier. // Finally try to restart the read transaction if we rolled it back earlier.
if (beginStmt) { if (beginStmt) {
nsresult rv = beginStmt.Borrow()->Execute(); QM_WARNONLY_TRY(
if (NS_SUCCEEDED(rv)) { ToResult(beginStmt.Borrow()->Execute())
mInReadTransaction = true; .andThen([&self = *this](const Ok) -> Result<Ok, nsresult> {
} else { self.mInReadTransaction = true;
NS_WARNING("Failed to restart read transaction!"); return Ok{};
} }));
} }
} }
@ -7373,9 +7381,7 @@ DatabaseConnection::AutoSavepoint::~AutoSavepoint() {
mDEBUGTransaction->GetMode() == IDBTransaction::Mode::Cleanup || mDEBUGTransaction->GetMode() == IDBTransaction::Mode::Cleanup ||
mDEBUGTransaction->GetMode() == IDBTransaction::Mode::VersionChange); mDEBUGTransaction->GetMode() == IDBTransaction::Mode::VersionChange);
if (NS_FAILED(mConnection->RollbackSavepoint())) { QM_WARNONLY_TRY(mConnection->RollbackSavepoint());
NS_WARNING("Failed to rollback savepoint!");
}
} }
} }
@ -7534,9 +7540,7 @@ void DatabaseConnection::UpdateRefcountFunction::DidCommit() {
entry.GetData()->MaybeUpdateDBRefs(); entry.GetData()->MaybeUpdateDBRefs();
} }
if (NS_FAILED(RemoveJournals(mJournalsToRemoveAfterCommit))) { QM_WARNONLY_TRY(RemoveJournals(mJournalsToRemoveAfterCommit));
NS_WARNING("RemoveJournals failed!");
}
} }
void DatabaseConnection::UpdateRefcountFunction::DidAbort() { void DatabaseConnection::UpdateRefcountFunction::DidAbort() {
@ -7546,9 +7550,7 @@ void DatabaseConnection::UpdateRefcountFunction::DidAbort() {
AUTO_PROFILER_LABEL("DatabaseConnection::UpdateRefcountFunction::DidAbort", AUTO_PROFILER_LABEL("DatabaseConnection::UpdateRefcountFunction::DidAbort",
DOM); DOM);
if (NS_FAILED(RemoveJournals(mJournalsToRemoveAfterAbort))) { QM_WARNONLY_TRY(RemoveJournals(mJournalsToRemoveAfterAbort));
NS_WARNING("RemoveJournals failed!");
}
} }
void DatabaseConnection::UpdateRefcountFunction::StartSavepoint() { void DatabaseConnection::UpdateRefcountFunction::StartSavepoint() {
@ -7696,7 +7698,7 @@ nsresult DatabaseConnection::UpdateRefcountFunction::RemoveJournals(
FileManager::GetFileForId(journalDirectory, journal); FileManager::GetFileForId(journalDirectory, journal);
IDB_TRY(OkIf(file), NS_ERROR_FAILURE); IDB_TRY(OkIf(file), NS_ERROR_FAILURE);
[&file] { IDB_TRY(file->Remove(false), QM_VOID); }(); QM_WARNONLY_TRY(file->Remove(false));
} }
return NS_OK; return NS_OK;
@ -9499,13 +9501,9 @@ void Database::Invalidate() {
Unused << SendInvalidate(); Unused << SendInvalidate();
} }
if (!InvalidateAll(mTransactions)) { QM_WARNONLY_TRY(OkIf(InvalidateAll(mTransactions)));
NS_WARNING("Failed to abort all transactions!");
}
if (!InvalidateAll(mMutableFiles)) { QM_WARNONLY_TRY(OkIf(InvalidateAll(mMutableFiles)));
NS_WARNING("Failed to abort all mutable files!");
}
MOZ_ALWAYS_TRUE(CloseInternal()); MOZ_ALWAYS_TRUE(CloseInternal());
} }
@ -12030,10 +12028,8 @@ void Cursor<CursorType>::SendResponseInternal(
KeyValueBase::ProcessFiles(aResponse, aFiles); KeyValueBase::ProcessFiles(aResponse, aFiles);
// Work around the deleted function by casting to the base class. // Work around the deleted function by casting to the base class.
auto* const base = static_cast<PBackgroundIDBCursorParent*>(this); QM_WARNONLY_TRY(OkIf(
if (!base->SendResponse(aResponse)) { static_cast<PBackgroundIDBCursorParent*>(this)->SendResponse(aResponse)));
NS_WARNING("Failed to send response!");
}
mCurrentlyRunningOp = nullptr; mCurrentlyRunningOp = nullptr;
} }
@ -12446,21 +12442,21 @@ Result<FileUsageType, nsresult> FileManager::GetUsage(nsIFile* aDirectory) {
if (NS_SUCCEEDED(rv)) { if (NS_SUCCEEDED(rv)) {
IDB_TRY_INSPECT( IDB_TRY_INSPECT(
const auto& thisUsage, const auto& thisUsage,
MOZ_TO_RESULT_INVOKE(file, GetFileSize) QM_OR_ELSE_WARN(
.map([](const int64_t fileSize) { MOZ_TO_RESULT_INVOKE(file, GetFileSize)
return FileUsageType(Some(uint64_t(fileSize))); .map([](const int64_t fileSize) {
}) return FileUsageType(Some(uint64_t(fileSize)));
.orElse( }),
[](const nsresult rv) -> Result<FileUsageType, nsresult> { ([](const nsresult rv) -> Result<FileUsageType, nsresult> {
if (rv == NS_ERROR_FILE_TARGET_DOES_NOT_EXIST || if (rv == NS_ERROR_FILE_TARGET_DOES_NOT_EXIST ||
rv == NS_ERROR_FILE_NOT_FOUND) { rv == NS_ERROR_FILE_NOT_FOUND) {
// If the file does no longer exist, treat it as // If the file does no longer exist, treat it as
// 0-sized. // 0-sized.
return FileUsageType{}; return FileUsageType{};
} }
return Err(rv); return Err(rv);
})); })));
usage += thisUsage; usage += thisUsage;
@ -12790,21 +12786,22 @@ nsresult QuotaClient::GetUsageForOriginInternal(
&aOriginMetadata](const nsString& subdirName) -> Result<Ok, nsresult> { &aOriginMetadata](const nsString& subdirName) -> Result<Ok, nsresult> {
// The directory must have the correct suffix. // The directory must have the correct suffix.
nsDependentSubstring subdirNameBase; nsDependentSubstring subdirNameBase;
IDB_TRY(([&subdirName, &subdirNameBase] { IDB_TRY(QM_OR_ELSE_WARN(
IDB_TRY_RETURN(OkIf(GetFilenameBase( ([&subdirName, &subdirNameBase] {
subdirName, kFileManagerDirectoryNameSuffix, IDB_TRY_RETURN(OkIf(GetFilenameBase(
subdirNameBase))); subdirName, kFileManagerDirectoryNameSuffix,
}() subdirNameBase)));
.orElse([&directory, &subdirName]( }()),
const NotOk) -> Result<Ok, nsresult> { ([&directory,
// If there is an unexpected directory in the idb &subdirName](const NotOk) -> Result<Ok, nsresult> {
// directory, trying to delete at first instead of // If there is an unexpected directory in the idb
// breaking the whole initialization. // directory, trying to delete at first instead of
IDB_TRY(DeleteFilesNoQuota(directory, subdirName), // breaking the whole initialization.
Err(NS_ERROR_UNEXPECTED)); IDB_TRY(DeleteFilesNoQuota(directory, subdirName),
Err(NS_ERROR_UNEXPECTED));
return Ok{}; return Ok{};
})), })),
Ok{}); Ok{});
if (obsoleteFilenames.Contains(subdirNameBase)) { if (obsoleteFilenames.Contains(subdirNameBase)) {
@ -12823,21 +12820,22 @@ nsresult QuotaClient::GetUsageForOriginInternal(
// If there is an unexpected directory in the idb directory, trying to // If there is an unexpected directory in the idb directory, trying to
// delete at first instead of breaking the whole initialization. // delete at first instead of breaking the whole initialization.
IDB_TRY(([&databaseFilenames, &subdirNameBase] { // XXX This is still somewhat quirky. It would be nice to make it
IDB_TRY_RETURN( // clear that the warning handler is infallible, which would also
OkIf(databaseFilenames.Contains(subdirNameBase))); // remove the need for the error type conversion.
}() QM_WARNONLY_TRY(QM_OR_ELSE_WARN(
.orElse([&directory, &subdirName]( OkIf(databaseFilenames.Contains(subdirNameBase))
const NotOk) -> Result<Ok, nsresult> { .mapErr([](const NotOk) { return NS_ERROR_FAILURE; }),
// XXX It seems if we really got here, we can fail the ([&directory,
// MOZ_ASSERT(!quotaManager->IsTemporaryStorageInitialized()); &subdirName](const nsresult) -> Result<Ok, nsresult> {
// assertion in DeleteFilesNoQuota. // XXX It seems if we really got here, we can fail the
IDB_TRY(DeleteFilesNoQuota(directory, subdirName), // MOZ_ASSERT(!quotaManager->IsTemporaryStorageInitialized());
Err(NS_ERROR_UNEXPECTED)); // assertion in DeleteFilesNoQuota.
IDB_TRY(DeleteFilesNoQuota(directory, subdirName),
Err(NS_ERROR_UNEXPECTED));
return Ok{}; return Ok{};
})), })));
Ok{});
return Ok{}; return Ok{};
})); }));
@ -12878,14 +12876,15 @@ nsresult QuotaClient::GetUsageForOriginInternal(
CloneFileAndAppend( CloneFileAndAppend(
*directory, databaseFilename + kSQLiteWALSuffix)); *directory, databaseFilename + kSQLiteWALSuffix));
IDB_TRY_INSPECT(const int64_t& walFileSize, IDB_TRY_INSPECT(
MOZ_TO_RESULT_INVOKE(walFile, GetFileSize) const int64_t& walFileSize,
.orElse([](const nsresult rv) { QM_OR_ELSE_WARN(MOZ_TO_RESULT_INVOKE(walFile, GetFileSize),
([](const nsresult rv) {
return (rv == NS_ERROR_FILE_NOT_FOUND || return (rv == NS_ERROR_FILE_NOT_FOUND ||
rv == NS_ERROR_FILE_TARGET_DOES_NOT_EXIST) rv == NS_ERROR_FILE_TARGET_DOES_NOT_EXIST)
? Result<int64_t, nsresult>{0} ? Result<int64_t, nsresult>{0}
: Err(rv); : Err(rv);
})); })));
MOZ_ASSERT(walFileSize >= 0); MOZ_ASSERT(walFileSize >= 0);
*aUsageInfo += DatabaseUsageType(Some(uint64_t(walFileSize))); *aUsageInfo += DatabaseUsageType(Some(uint64_t(walFileSize)));
} }
@ -14248,31 +14247,33 @@ void DatabaseMaintenance::FullVacuum(mozIStorageConnection& aConnection,
return; return;
} }
IDB_TRY(aConnection.ExecuteSimpleSQL("VACUUM;"_ns), QM_VOID); QM_WARNONLY_TRY(([&]() -> Result<Ok, nsresult> {
IDB_TRY(aConnection.ExecuteSimpleSQL("VACUUM;"_ns));
const PRTime vacuumTime = PR_Now(); const PRTime vacuumTime = PR_Now();
MOZ_ASSERT(vacuumTime > 0); MOZ_ASSERT(vacuumTime > 0);
IDB_TRY_INSPECT(const int64_t& fileSize, IDB_TRY_INSPECT(const int64_t& fileSize,
MOZ_TO_RESULT_INVOKE(aDatabaseFile, GetFileSize), QM_VOID); MOZ_TO_RESULT_INVOKE(aDatabaseFile, GetFileSize));
MOZ_ASSERT(fileSize > 0); MOZ_ASSERT(fileSize > 0);
// The parameter names are not used, parameters are bound by index only // The parameter names are not used, parameters are bound by index only
// locally in the same function. // locally in the same function.
IDB_TRY_INSPECT(const auto& stmt, IDB_TRY_INSPECT(const auto& stmt, MOZ_TO_RESULT_INVOKE_TYPED(
MOZ_TO_RESULT_INVOKE_TYPED(nsCOMPtr<mozIStorageStatement>, nsCOMPtr<mozIStorageStatement>,
aConnection, CreateStatement, aConnection, CreateStatement,
"UPDATE database " "UPDATE database "
"SET last_vacuum_time = :time" "SET last_vacuum_time = :time"
", last_vacuum_size = :size;"_ns), ", last_vacuum_size = :size;"_ns));
QM_VOID);
IDB_TRY(stmt->BindInt64ByIndex(0, vacuumTime), QM_VOID); IDB_TRY(stmt->BindInt64ByIndex(0, vacuumTime));
IDB_TRY(stmt->BindInt64ByIndex(1, fileSize), QM_VOID); IDB_TRY(stmt->BindInt64ByIndex(1, fileSize));
IDB_TRY(stmt->Execute(), QM_VOID); IDB_TRY(stmt->Execute());
return Ok{};
}()));
} }
void DatabaseMaintenance::RunOnOwningThread() { void DatabaseMaintenance::RunOnOwningThread() {
@ -14614,29 +14615,28 @@ nsresult DatabaseOperationBase::InsertIndexTableRows(
IDB_TRY(aObjectStoreKey.BindToStatement(&*borrowedStmt, IDB_TRY(aObjectStoreKey.BindToStatement(&*borrowedStmt,
kStmtParamNameObjectDataKey)); kStmtParamNameObjectDataKey));
IDB_TRY(MOZ_TO_RESULT_INVOKE(&*borrowedStmt, Execute) QM_TRY(QM_OR_ELSE_WARN(
.orElse([&info, index, ToResult(borrowedStmt->Execute()),
&aIndexValues](nsresult rv) -> Result<Ok, nsresult> { ([&info, index, &aIndexValues](nsresult rv) -> Result<Ok, nsresult> {
if (rv == NS_ERROR_STORAGE_CONSTRAINT && info.mUnique) { if (rv == NS_ERROR_STORAGE_CONSTRAINT && info.mUnique) {
// If we're inserting multiple entries for the same unique // If we're inserting multiple entries for the same unique
// index, then we might have failed to insert due to // index, then we might have failed to insert due to
// colliding with another entry for the same index in which // colliding with another entry for the same index in which
// case we should ignore it. // case we should ignore it.
for (int32_t index2 = int32_t(index) - 1; for (int32_t index2 = int32_t(index) - 1;
index2 >= 0 && index2 >= 0 && aIndexValues[index2].mIndexId == info.mIndexId;
aIndexValues[index2].mIndexId == info.mIndexId; --index2) {
--index2) { if (info.mPosition == aIndexValues[index2].mPosition) {
if (info.mPosition == aIndexValues[index2].mPosition) { // We found a key with the same value for the same
// We found a key with the same value for the same // index. So we must have had a collision with a value
// index. So we must have had a collision with a value // we just inserted.
// we just inserted. return Ok{};
return Ok{}; }
} }
} }
}
return Err(rv); return Err(rv);
})); })));
} }
return NS_OK; return NS_OK;

Просмотреть файл

@ -9,6 +9,7 @@
#include "FileInfoT.h" #include "FileInfoT.h"
#include "mozilla/dom/quota/QuotaCommon.h"
#include "mozilla/Mutex.h" #include "mozilla/Mutex.h"
#include "nsIFile.h" #include "nsIFile.h"
@ -94,10 +95,7 @@ void FileInfoT<FileManager>::UpdateReferences(ThreadSafeAutoRefCnt& aRefCount,
if (needsCleanup) { if (needsCleanup) {
if (aSyncDeleteFile) { if (aSyncDeleteFile) {
nsresult rv = mFileManager->SyncDeleteFile(Id()); QM_WARNONLY_TRY(mFileManager->SyncDeleteFile(Id()));
if (NS_FAILED(rv)) {
NS_WARNING("FileManager cleanup failed!");
}
} else { } else {
Cleanup(); Cleanup();
} }
@ -136,11 +134,7 @@ bool FileInfoT<FileManager>::LockedClearDBRefs(
template <typename FileManager> template <typename FileManager>
void FileInfoT<FileManager>::Cleanup() { void FileInfoT<FileManager>::Cleanup() {
int64_t id = Id(); QM_WARNONLY_TRY(mFileManager->AsyncDeleteFile(Id()));
if (NS_FAILED(mFileManager->AsyncDeleteFile(id))) {
NS_WARNING("Failed to delete file asynchronously!");
}
} }
template <typename FileManager> template <typename FileManager>

Просмотреть файл

@ -203,12 +203,10 @@ RefPtr<IDBDatabase> IDBDatabase::Create(IDBOpenDBRequest* aRequest,
obsSvc->AddObserver(observer, kWindowObserverTopic, false)); obsSvc->AddObserver(observer, kWindowObserverTopic, false));
// These topics are not crucial. // These topics are not crucial.
if (NS_FAILED(obsSvc->AddObserver(observer, kCycleCollectionObserverTopic, QM_WARNONLY_TRY(
false)) || obsSvc->AddObserver(observer, kCycleCollectionObserverTopic, false));
NS_FAILED(obsSvc->AddObserver(observer, kMemoryPressureObserverTopic, QM_WARNONLY_TRY(
false))) { obsSvc->AddObserver(observer, kMemoryPressureObserverTopic, false));
NS_WARNING("Failed to add additional memory observers!");
}
db->mObserver = std::move(observer); db->mObserver = std::move(observer);
} }
@ -369,11 +367,14 @@ RefPtr<IDBObjectStore> IDBDatabase::CreateObjectStore(
return nullptr; return nullptr;
} }
// XXX This didn't use to warn before in case of a error. Should we remove the QM_NOTEONLY_TRY_UNWRAP(const auto maybeKeyPath,
// warning again? KeyPath::Parse(aOptionalParameters.mKeyPath));
IDB_TRY_INSPECT(const auto& keyPath, if (!maybeKeyPath) {
KeyPath::Parse(aOptionalParameters.mKeyPath), nullptr, aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
[&aRv](const auto&) { aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR); }); return nullptr;
}
const auto& keyPath = maybeKeyPath.ref();
auto& objectStores = mSpec->objectStores(); auto& objectStores = mSpec->objectStores();
const auto end = objectStores.cend(); const auto end = objectStores.cend();

Просмотреть файл

@ -1378,8 +1378,6 @@ RefPtr<IDBIndex> IDBObjectStore::CreateIndex(
return nullptr; return nullptr;
} }
// XXX This didn't use to warn before in case of a error. Should we remove the
// warning again?
const auto checkValid = [](const auto& keyPath) -> Result<KeyPath, nsresult> { const auto checkValid = [](const auto& keyPath) -> Result<KeyPath, nsresult> {
if (!keyPath.IsValid()) { if (!keyPath.IsValid()) {
return Err(NS_ERROR_DOM_SYNTAX_ERR); return Err(NS_ERROR_DOM_SYNTAX_ERR);
@ -1388,8 +1386,8 @@ RefPtr<IDBIndex> IDBObjectStore::CreateIndex(
return keyPath; return keyPath;
}; };
IDB_TRY_INSPECT( QM_NOTEONLY_TRY_UNWRAP(
const auto& keyPath, const auto maybeKeyPath,
([&aKeyPath, checkValid]() -> Result<KeyPath, nsresult> { ([&aKeyPath, checkValid]() -> Result<KeyPath, nsresult> {
if (aKeyPath.IsString()) { if (aKeyPath.IsString()) {
IDB_TRY_RETURN( IDB_TRY_RETURN(
@ -1403,8 +1401,13 @@ RefPtr<IDBIndex> IDBObjectStore::CreateIndex(
IDB_TRY_RETURN( IDB_TRY_RETURN(
KeyPath::Parse(aKeyPath.GetAsStringSequence()).andThen(checkValid)); KeyPath::Parse(aKeyPath.GetAsStringSequence()).andThen(checkValid));
})(), })());
nullptr, [&aRv](const auto&) { aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR); }); if (!maybeKeyPath) {
aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
return nullptr;
}
const auto& keyPath = maybeKeyPath.ref();
if (aOptionalParameters.mMultiEntry && keyPath.IsArray()) { if (aOptionalParameters.mMultiEntry && keyPath.IsArray()) {
aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR); aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);

Просмотреть файл

@ -438,9 +438,9 @@ nsresult SetDefaultPragmas(mozIStorageConnection* aConnection) {
if (kSQLiteGrowthIncrement) { if (kSQLiteGrowthIncrement) {
// This is just an optimization so ignore the failure if the disk is // This is just an optimization so ignore the failure if the disk is
// currently too full. // currently too full.
LS_TRY( QM_TRY(QM_OR_ELSE_WARN(ToResult(aConnection->SetGrowthIncrement(
ToResult(aConnection->SetGrowthIncrement(kSQLiteGrowthIncrement, ""_ns)) kSQLiteGrowthIncrement, ""_ns)),
.orElse(ErrToDefaultOkOrErr<NS_ERROR_FILE_TOO_BIG, Ok>)); ErrToDefaultOkOrErr<NS_ERROR_FILE_TOO_BIG>));
} }
#endif // LS_MOBILE #endif // LS_MOBILE
@ -463,23 +463,25 @@ Result<nsCOMPtr<mozIStorageConnection>, nsresult> CreateStorageConnection(
LS_TRY_UNWRAP( LS_TRY_UNWRAP(
auto connection, auto connection,
MOZ_TO_RESULT_INVOKE_TYPED(nsCOMPtr<mozIStorageConnection>, QM_OR_ELSE_WARN(
storageService, OpenDatabase, &aDBFile) MOZ_TO_RESULT_INVOKE_TYPED(nsCOMPtr<mozIStorageConnection>,
.orElse([&aUsageFile, &aDBFile, &aCorruptedFileHandler, storageService, OpenDatabase, &aDBFile),
&storageService](const nsresult rv) ([&aUsageFile, &aDBFile, &aCorruptedFileHandler,
-> Result<nsCOMPtr<mozIStorageConnection>, nsresult> { &storageService](const nsresult rv)
-> Result<nsCOMPtr<mozIStorageConnection>, nsresult> {
if (IsDatabaseCorruptionError(rv)) { if (IsDatabaseCorruptionError(rv)) {
// Remove the usage file first (it might not exist at all due // Remove the usage file first (it might not exist at all due
// to corrupted state, which is ignored here). // to corrupted state, which is ignored here).
LS_TRY(ToResult(aUsageFile.Remove(false)) QM_TRY(QM_OR_ELSE_WARN(
.orElse([](const nsresult rv) -> Result<Ok, nsresult> { ToResult(aUsageFile.Remove(false)),
if (rv == NS_ERROR_FILE_NOT_FOUND || ([](const nsresult rv) -> Result<Ok, nsresult> {
rv == NS_ERROR_FILE_TARGET_DOES_NOT_EXIST) { if (rv == NS_ERROR_FILE_NOT_FOUND ||
return Ok{}; rv == NS_ERROR_FILE_TARGET_DOES_NOT_EXIST) {
} return Ok{};
}
return Err(rv); return Err(rv);
})); })));
// Call the corrupted file handler before trying to remove the // Call the corrupted file handler before trying to remove the
// database file, which might fail. // database file, which might fail.
@ -493,7 +495,7 @@ Result<nsCOMPtr<mozIStorageConnection>, nsresult> CreateStorageConnection(
&aDBFile)); &aDBFile));
} }
return Err(rv); return Err(rv);
})); })));
LS_TRY(SetDefaultPragmas(connection)); LS_TRY(SetDefaultPragmas(connection));
@ -678,10 +680,11 @@ CreateArchiveStorageConnection(const nsAString& aStoragePath) {
LS_TRY_UNWRAP( LS_TRY_UNWRAP(
auto connection, auto connection,
MOZ_TO_RESULT_INVOKE_TYPED(nsCOMPtr<mozIStorageConnection>, ss, QM_OR_ELSE_WARN(
OpenUnsharedDatabase, archiveFile) MOZ_TO_RESULT_INVOKE_TYPED(nsCOMPtr<mozIStorageConnection>, ss,
.orElse([](const nsresult rv) OpenUnsharedDatabase, archiveFile),
-> Result<nsCOMPtr<mozIStorageConnection>, nsresult> { ([](const nsresult rv)
-> Result<nsCOMPtr<mozIStorageConnection>, nsresult> {
if (IsDatabaseCorruptionError(rv)) { if (IsDatabaseCorruptionError(rv)) {
// Don't throw an error, leave a corrupted ls-archive database as // Don't throw an error, leave a corrupted ls-archive database as
// it is. // it is.
@ -689,7 +692,7 @@ CreateArchiveStorageConnection(const nsAString& aStoragePath) {
} }
return Err(rv); return Err(rv);
})); })));
if (connection) { if (connection) {
const nsresult rv = StorageDBUpdater::Update(connection); const nsresult rv = StorageDBUpdater::Update(connection);
@ -814,10 +817,11 @@ Result<nsCOMPtr<mozIStorageConnection>, nsresult> CreateShadowStorageConnection(
LS_TRY_UNWRAP( LS_TRY_UNWRAP(
auto connection, auto connection,
MOZ_TO_RESULT_INVOKE_TYPED(nsCOMPtr<mozIStorageConnection>, ss, QM_OR_ELSE_WARN(
OpenUnsharedDatabase, shadowFile) MOZ_TO_RESULT_INVOKE_TYPED(nsCOMPtr<mozIStorageConnection>, ss,
.orElse([&shadowFile, &ss](const nsresult rv) OpenUnsharedDatabase, shadowFile),
-> Result<nsCOMPtr<mozIStorageConnection>, nsresult> { ([&shadowFile, &ss](const nsresult rv)
-> Result<nsCOMPtr<mozIStorageConnection>, nsresult> {
if (IsDatabaseCorruptionError(rv)) { if (IsDatabaseCorruptionError(rv)) {
LS_TRY(shadowFile->Remove(false)); LS_TRY(shadowFile->Remove(false));
@ -827,7 +831,7 @@ Result<nsCOMPtr<mozIStorageConnection>, nsresult> CreateShadowStorageConnection(
} }
return Err(rv); return Err(rv);
})); })));
LS_TRY(SetShadowJournalMode(connection)); LS_TRY(SetShadowJournalMode(connection));
@ -845,23 +849,22 @@ Result<nsCOMPtr<mozIStorageConnection>, nsresult> CreateShadowStorageConnection(
// complicated than it should be. Maybe these two methods can be merged (which // complicated than it should be. Maybe these two methods can be merged (which
// would mean that a parameter must be added that indicates whether it's // would mean that a parameter must be added that indicates whether it's
// handling the shadow file or not). // handling the shadow file or not).
LS_TRY(ToResult(StorageDBUpdater::Update(connection)) QM_TRY(QM_OR_ELSE_WARN(
.orElse([&connection, &shadowFile, ToResult(StorageDBUpdater::Update(connection)),
&ss](const nsresult) -> Result<Ok, nsresult> { ([&connection, &shadowFile, &ss](const nsresult) -> Result<Ok, nsresult> {
LS_TRY(connection->Close()); LS_TRY(connection->Close());
LS_TRY(shadowFile->Remove(false)); LS_TRY(shadowFile->Remove(false));
LS_TRY_UNWRAP(connection, LS_TRY_UNWRAP(connection, MOZ_TO_RESULT_INVOKE_TYPED(
MOZ_TO_RESULT_INVOKE_TYPED( nsCOMPtr<mozIStorageConnection>, ss,
nsCOMPtr<mozIStorageConnection>, ss, OpenUnsharedDatabase, shadowFile));
OpenUnsharedDatabase, shadowFile));
LS_TRY(SetShadowJournalMode(connection)); LS_TRY(SetShadowJournalMode(connection));
LS_TRY(StorageDBUpdater::CreateCurrentSchema(connection)); LS_TRY(StorageDBUpdater::CreateCurrentSchema(connection));
return Ok{}; return Ok{};
})); })));
return connection; return connection;
} }
@ -960,19 +963,19 @@ Result<bool, nsresult> ExistsAsFile(nsIFile& aFile) {
// the path exists. // the path exists.
LS_TRY_INSPECT( LS_TRY_INSPECT(
const auto& res, const auto& res,
MOZ_TO_RESULT_INVOKE(aFile, IsDirectory) QM_OR_ELSE_WARN(
.map([](const bool isDirectory) { MOZ_TO_RESULT_INVOKE(aFile, IsDirectory)
return isDirectory ? ExistsAsFileResult::IsDirectory .map([](const bool isDirectory) {
: ExistsAsFileResult::IsFile; return isDirectory ? ExistsAsFileResult::IsDirectory
}) : ExistsAsFileResult::IsFile;
.orElse( }),
[](const nsresult rv) -> Result<ExistsAsFileResult, nsresult> { ([](const nsresult rv) -> Result<ExistsAsFileResult, nsresult> {
if (rv != NS_ERROR_FILE_NOT_FOUND && if (rv != NS_ERROR_FILE_NOT_FOUND &&
rv != NS_ERROR_FILE_TARGET_DOES_NOT_EXIST) { rv != NS_ERROR_FILE_TARGET_DOES_NOT_EXIST) {
return Err(rv); return Err(rv);
} }
return ExistsAsFileResult::DoesNotExist; return ExistsAsFileResult::DoesNotExist;
})); })));
LS_TRY(OkIf(res != ExistsAsFileResult::IsDirectory), Err(NS_ERROR_FAILURE)); LS_TRY(OkIf(res != ExistsAsFileResult::IsDirectory), Err(NS_ERROR_FAILURE));
@ -3079,17 +3082,16 @@ void InitializeLocalStorage() {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!gLocalStorageInitialized); MOZ_ASSERT(!gLocalStorageInitialized);
// XXX Isn't this redundant? It's already done in InitializeQuotaManager.
if (!QuotaManager::IsRunningGTests()) { if (!QuotaManager::IsRunningGTests()) {
// This service has to be started on the main thread currently. // This service has to be started on the main thread currently.
nsCOMPtr<mozIStorageService> ss; const nsCOMPtr<mozIStorageService> ss =
if (NS_WARN_IF(!(ss = do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID)))) { do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID);
NS_WARNING("Failed to get storage service!");
} QM_WARNONLY_TRY(OkIf(ss));
} }
if (NS_FAILED(QuotaClient::Initialize())) { QM_WARNONLY_TRY(QuotaClient::Initialize());
NS_WARNING("Failed to initialize quota client!");
}
Preferences::RegisterCallbackAndCall(ShadowWritesPrefChangedCallback, Preferences::RegisterCallbackAndCall(ShadowWritesPrefChangedCallback,
kShadowWritesPref); kShadowWritesPref);
@ -8102,31 +8104,29 @@ Result<UsageInfo, nsresult> QuotaClient::InitOrigin(
([fileExists, usageFileExists, &file, &usageFile, &usageJournalFile, ([fileExists, usageFileExists, &file, &usageFile, &usageJournalFile,
&aOriginMetadata]() -> Result<UsageInfo, nsresult> { &aOriginMetadata]() -> Result<UsageInfo, nsresult> {
if (fileExists) { if (fileExists) {
LS_TRY_RETURN( LS_TRY_RETURN(QM_OR_ELSE_WARN(
// To simplify control flow, we call LoadUsageFile unconditionally // To simplify control flow, we call LoadUsageFile unconditionally
// here, even though it will necessarily fail if usageFileExists // here, even though it will necessarily fail if usageFileExists
// is false. // is false.
LoadUsageFile(*usageFile) LoadUsageFile(*usageFile),
.orElse([&file, &usageFile, &usageJournalFile, ([&file, &usageFile, &usageJournalFile, &aOriginMetadata](
&aOriginMetadata]( const nsresult) -> Result<UsageInfo, nsresult> {
const nsresult) -> Result<UsageInfo, nsresult> { LS_TRY_INSPECT(
LS_TRY_INSPECT( const auto& connection,
const auto& connection, CreateStorageConnection(*file, *usageFile,
CreateStorageConnection( aOriginMetadata.mOrigin, [] {}));
*file, *usageFile, aOriginMetadata.mOrigin, [] {}));
LS_TRY_INSPECT( LS_TRY_INSPECT(const int64_t& usage,
const int64_t& usage, GetUsage(*connection,
GetUsage(*connection, /* aArchivedOriginScope */ nullptr));
/* aArchivedOriginScope */ nullptr));
LS_TRY(UpdateUsageFile(usageFile, usageJournalFile, usage)); LS_TRY(UpdateUsageFile(usageFile, usageJournalFile, usage));
LS_TRY(usageJournalFile->Remove(false)); LS_TRY(usageJournalFile->Remove(false));
MOZ_ASSERT(usage >= 0); MOZ_ASSERT(usage >= 0);
return UsageInfo{DatabaseUsageType(Some(uint64_t(usage)))}; return UsageInfo{DatabaseUsageType(Some(uint64_t(usage)))};
})); })));
} }
if (usageFileExists) { if (usageFileExists) {
@ -8741,12 +8741,10 @@ AutoWriteTransaction::~AutoWriteTransaction() {
MOZ_COUNT_DTOR(mozilla::dom::AutoWriteTransaction); MOZ_COUNT_DTOR(mozilla::dom::AutoWriteTransaction);
if (mConnection) { if (mConnection) {
if (NS_FAILED(mConnection->RollbackWriteTransaction())) { QM_WARNONLY_TRY(mConnection->RollbackWriteTransaction());
NS_WARNING("Failed to rollback write transaction!");
}
if (mShadowWrites && NS_FAILED(DetachShadowDatabaseAndUnlock())) { if (mShadowWrites) {
NS_WARNING("Failed to detach shadow database!"); QM_WARNONLY_TRY(DetachShadowDatabaseAndUnlock());
} }
} }
} }

Просмотреть файл

@ -429,24 +429,22 @@ nsresult InvalidateCache(mozIStorageConnection& aConnection) {
static constexpr auto kDeleteCacheQuery = "DELETE FROM origin;"_ns; static constexpr auto kDeleteCacheQuery = "DELETE FROM origin;"_ns;
static constexpr auto kSetInvalidFlagQuery = "UPDATE cache SET valid = 0"_ns; static constexpr auto kSetInvalidFlagQuery = "UPDATE cache SET valid = 0"_ns;
// XXX Use QM_TRY_OR_WARN here in/after Bug 1686191. QM_TRY(QM_OR_ELSE_WARN(
QM_TRY(([&]() -> Result<Ok, nsresult> { ([&]() -> Result<Ok, nsresult> {
mozStorageTransaction transaction(&aConnection, false); mozStorageTransaction transaction(&aConnection, false);
QM_TRY(transaction.Start()); QM_TRY(transaction.Start());
QM_TRY(aConnection.ExecuteSimpleSQL(kDeleteCacheQuery)); QM_TRY(aConnection.ExecuteSimpleSQL(kDeleteCacheQuery));
QM_TRY(aConnection.ExecuteSimpleSQL(kSetInvalidFlagQuery)); QM_TRY(aConnection.ExecuteSimpleSQL(kSetInvalidFlagQuery));
QM_TRY(transaction.Commit()); QM_TRY(transaction.Commit());
return Ok{}; return Ok{};
}() }()),
.orElse([&](const nsresult rv) -> Result<Ok, nsresult> { ([&](const nsresult rv) -> Result<Ok, nsresult> {
QM_TRY(aConnection.ExecuteSimpleSQL( QM_TRY(aConnection.ExecuteSimpleSQL(kSetInvalidFlagQuery));
kSetInvalidFlagQuery));
return Ok{};
})));
return Ok{};
})));
return NS_OK; return NS_OK;
} }
@ -571,21 +569,21 @@ Result<nsCOMPtr<mozIStorageConnection>, nsresult> CreateWebAppsStoreConnection(
return nsCOMPtr<mozIStorageConnection>{}; return nsCOMPtr<mozIStorageConnection>{};
} }
QM_TRY_INSPECT( QM_TRY_INSPECT(const auto& connection,
const auto& connection, QM_OR_ELSE_WARN(
MOZ_TO_RESULT_INVOKE_TYPED(nsCOMPtr<mozIStorageConnection>, MOZ_TO_RESULT_INVOKE_TYPED(
aStorageService, OpenUnsharedDatabase, nsCOMPtr<mozIStorageConnection>, aStorageService,
&aWebAppsStoreFile) OpenUnsharedDatabase, &aWebAppsStoreFile),
.orElse([](const nsresult rv) ([](const nsresult rv)
-> Result<nsCOMPtr<mozIStorageConnection>, nsresult> { -> Result<nsCOMPtr<mozIStorageConnection>, nsresult> {
if (IsDatabaseCorruptionError(rv)) { if (IsDatabaseCorruptionError(rv)) {
// Don't throw an error, leave a corrupted webappsstore database // Don't throw an error, leave a corrupted webappsstore
// as it is. // database as it is.
return nsCOMPtr<mozIStorageConnection>{}; return nsCOMPtr<mozIStorageConnection>{};
} }
return Err(rv); return Err(rv);
})); })));
if (connection) { if (connection) {
// Don't propagate an error, leave a non-updateable webappsstore database as // Don't propagate an error, leave a non-updateable webappsstore database as
@ -2391,12 +2389,12 @@ int64_t GetLastModifiedTime(PersistenceType aPersistenceType, nsIFile& aFile) {
Result<bool, nsresult> EnsureDirectory(nsIFile& aDirectory) { Result<bool, nsresult> EnsureDirectory(nsIFile& aDirectory) {
AssertIsOnIOThread(); AssertIsOnIOThread();
// TODO: Convert to mapOrElse once mozilla::Result supports it.
QM_TRY_INSPECT( QM_TRY_INSPECT(
const auto& exists, const auto& exists,
MOZ_TO_RESULT_INVOKE(aDirectory, Create, nsIFile::DIRECTORY_TYPE, 0755) QM_OR_ELSE_WARN(MOZ_TO_RESULT_INVOKE(aDirectory, Create,
.andThen(OkToOk<false>) nsIFile::DIRECTORY_TYPE, 0755)
.orElse(ErrToOkOrErr<NS_ERROR_FILE_ALREADY_EXISTS, true>)); .map([](Ok) { return false; }),
(ErrToOkOrErr<NS_ERROR_FILE_ALREADY_EXISTS, true>)));
if (exists) { if (exists) {
QM_TRY_INSPECT(const bool& isDirectory, QM_TRY_INSPECT(const bool& isDirectory,
@ -2631,17 +2629,19 @@ void InitializeQuotaManager() {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!gQuotaManagerInitialized); MOZ_ASSERT(!gQuotaManagerInitialized);
#ifdef QM_ENABLE_SCOPED_LOG_EXTRA_INFO
ScopedLogExtraInfo::Initialize();
#endif
if (!QuotaManager::IsRunningGTests()) { if (!QuotaManager::IsRunningGTests()) {
// This service has to be started on the main thread currently. // This service has to be started on the main thread currently.
nsCOMPtr<mozIStorageService> ss; const nsCOMPtr<mozIStorageService> ss =
if (NS_WARN_IF(!(ss = do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID)))) { do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID);
NS_WARNING("Failed to get storage service!");
} QM_WARNONLY_TRY(OkIf(ss));
} }
if (NS_FAILED(QuotaManager::Initialize())) { QM_WARNONLY_TRY(QuotaManager::Initialize());
NS_WARNING("Failed to initialize quota manager!");
}
#ifdef DEBUG #ifdef DEBUG
gQuotaManagerInitialized = true; gQuotaManagerInitialized = true;
@ -3225,10 +3225,6 @@ QuotaManager::~QuotaManager() {
nsresult QuotaManager::Initialize() { nsresult QuotaManager::Initialize() {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
#ifdef QM_ENABLE_SCOPED_LOG_EXTRA_INFO
ScopedLogExtraInfo::Initialize();
#endif
nsresult rv = Observer::Initialize(); nsresult rv = Observer::Initialize();
if (NS_WARN_IF(NS_FAILED(rv))) { if (NS_WARN_IF(NS_FAILED(rv))) {
return rv; return rv;
@ -3798,9 +3794,7 @@ void QuotaManager::Shutdown() {
} }
// Cancel the timer regardless of whether it actually fired. // Cancel the timer regardless of whether it actually fired.
if (NS_FAILED((*mShutdownTimer)->Cancel())) { QM_WARNONLY_TRY((*mShutdownTimer)->Cancel());
NS_WARNING("Failed to cancel shutdown timer!");
}
// NB: It's very important that runnable is destroyed on this thread // NB: It's very important that runnable is destroyed on this thread
// (i.e. after we join the IO thread) because we can't release the // (i.e. after we join the IO thread) because we can't release the
@ -3812,14 +3806,10 @@ void QuotaManager::Shutdown() {
MOZ_ASSERT(runnable); MOZ_ASSERT(runnable);
// Give clients a chance to cleanup IO thread only objects. // Give clients a chance to cleanup IO thread only objects.
if (NS_FAILED((*mIOThread)->Dispatch(runnable, NS_DISPATCH_NORMAL))) { QM_WARNONLY_TRY((*mIOThread)->Dispatch(runnable, NS_DISPATCH_NORMAL));
NS_WARNING("Failed to dispatch runnable!");
}
// Make sure to join with our IO thread. // Make sure to join with our IO thread.
if (NS_FAILED((*mIOThread)->Shutdown())) { QM_WARNONLY_TRY((*mIOThread)->Shutdown());
NS_WARNING("Failed to shutdown IO thread!");
}
for (RefPtr<DirectoryLockImpl>& lock : mPendingDirectoryLocks) { for (RefPtr<DirectoryLockImpl>& lock : mPendingDirectoryLocks) {
lock->Invalidate(); lock->Invalidate();
@ -4620,21 +4610,14 @@ QuotaManager::LoadFullOriginMetadataWithRestore(nsIFile* aDirectory) {
const auto& persistenceType = maybePersistenceType.value(); const auto& persistenceType = maybePersistenceType.value();
QM_TRY_UNWRAP(auto maybeFirstAttemptResult, QM_TRY_RETURN(QM_OR_ELSE_WARN(
([&]() -> Result<Maybe<FullOriginMetadata>, nsresult> { LoadFullOriginMetadata(aDirectory, persistenceType),
QM_TRY_RETURN( ([&aDirectory, &persistenceType,
LoadFullOriginMetadata(aDirectory, persistenceType) this](const nsresult rv) -> Result<FullOriginMetadata, nsresult> {
.map(Some<FullOriginMetadata, FullOriginMetadata>), QM_TRY(RestoreDirectoryMetadata2(aDirectory));
Maybe<FullOriginMetadata>{});
}()));
if (!maybeFirstAttemptResult) { QM_TRY_RETURN(LoadFullOriginMetadata(aDirectory, persistenceType));
QM_TRY(RestoreDirectoryMetadata2(aDirectory)); })));
QM_TRY_RETURN(LoadFullOriginMetadata(aDirectory, persistenceType));
}
return maybeFirstAttemptResult.extract();
} }
nsresult QuotaManager::InitializeRepository(PersistenceType aPersistenceType) { nsresult QuotaManager::InitializeRepository(PersistenceType aPersistenceType) {
@ -4728,26 +4711,26 @@ nsresult QuotaManager::InitializeRepository(PersistenceType aPersistenceType) {
// they won't be accessed after initialization. // they won't be accessed after initialization.
} }
QM_TRY( QM_TRY(QM_OR_ELSE_WARN(
ToResult(InitializeOrigin( ToResult(InitializeOrigin(
aPersistenceType, metadata, aPersistenceType, metadata,
metadata.mLastAccessTime, metadata.mLastAccessTime, metadata.mPersisted,
metadata.mPersisted, childDirectory)) childDirectory)),
.orElse([&childDirectory](const nsresult rv) ([&childDirectory](
-> Result<Ok, nsresult> { const nsresult rv) -> Result<Ok, nsresult> {
if (IsDatabaseCorruptionError(rv)) { if (IsDatabaseCorruptionError(rv)) {
// If the origin can't be initialized due // If the origin can't be initialized due to
// to corruption, this is a permanent // corruption, this is a permanent
// condition, and we need to remove all // condition, and we need to remove all data
// data for the origin on disk. // for the origin on disk.
QM_TRY(childDirectory->Remove(true)); QM_TRY(childDirectory->Remove(true));
return Ok{}; return Ok{};
} }
return Err(rv); return Err(rv);
})); })));
break; break;
} }
@ -6004,11 +5987,13 @@ nsresult QuotaManager::EnsureStorageIsInitialized() {
MOZ_SELECT_OVERLOAD(do_GetService), MOZ_SELECT_OVERLOAD(do_GetService),
MOZ_STORAGE_SERVICE_CONTRACTID)); MOZ_STORAGE_SERVICE_CONTRACTID));
QM_TRY_UNWRAP(auto connection, QM_TRY_UNWRAP(
MOZ_TO_RESULT_INVOKE_TYPED(nsCOMPtr<mozIStorageConnection>, ss, auto connection,
OpenUnsharedDatabase, storageFile) QM_OR_ELSE_WARN(
.orElse(FilterDatabaseCorruptionError< MOZ_TO_RESULT_INVOKE_TYPED(nsCOMPtr<mozIStorageConnection>, ss,
nullptr, nsCOMPtr<mozIStorageConnection>>)); OpenUnsharedDatabase, storageFile),
(FilterDatabaseCorruptionError<nullptr,
nsCOMPtr<mozIStorageConnection>>)));
if (!connection) { if (!connection) {
// Nuke the database file. // Nuke the database file.
@ -6031,14 +6016,14 @@ nsresult QuotaManager::EnsureStorageIsInitialized() {
GetLocalStorageArchiveFile(*mStoragePath)); GetLocalStorageArchiveFile(*mStoragePath));
if (CachedNextGenLocalStorageEnabled()) { if (CachedNextGenLocalStorageEnabled()) {
QM_TRY(MaybeCreateOrUpgradeLocalStorageArchive(*lsArchiveFile) QM_TRY(QM_OR_ELSE_WARN(
.orElse([&](const nsresult rv) -> Result<Ok, nsresult> { MaybeCreateOrUpgradeLocalStorageArchive(*lsArchiveFile),
if (IsDatabaseCorruptionError(rv)) { ([&](const nsresult rv) -> Result<Ok, nsresult> {
QM_TRY_RETURN( if (IsDatabaseCorruptionError(rv)) {
CreateEmptyLocalStorageArchive(*lsArchiveFile)); QM_TRY_RETURN(CreateEmptyLocalStorageArchive(*lsArchiveFile));
} }
return Err(rv); return Err(rv);
})); })));
} else { } else {
QM_TRY(MaybeRemoveLocalStorageDataAndArchive(*lsArchiveFile)); QM_TRY(MaybeRemoveLocalStorageDataAndArchive(*lsArchiveFile));
} }
@ -9009,11 +8994,9 @@ void ClearRequestBase::DeleteFiles(QuotaManager& aQuotaManager,
// We can't guarantee that this will always succeed on // We can't guarantee that this will always succeed on
// Windows... // Windows...
if (NS_FAILED((file->Remove(true)))) { QM_WARNONLY_TRY(file->Remove(true), [&](const auto&) {
NS_WARNING("Failed to remove directory, retrying later.");
directoriesForRemovalRetry.AppendElement(std::move(file)); directoriesForRemovalRetry.AppendElement(std::move(file));
} });
const bool initialized = const bool initialized =
aPersistenceType == PERSISTENCE_TYPE_PERSISTENT aPersistenceType == PERSISTENCE_TYPE_PERSISTENT
@ -10563,22 +10546,20 @@ nsresult CreateOrUpgradeDirectoryMetadataHelper::MaybeUpgradeOriginDirectory(
QM_TRY_INSPECT(const auto& idbDirectory, QM_TRY_INSPECT(const auto& idbDirectory,
CloneFileAndAppend(*aDirectory, idbDirectoryName)); CloneFileAndAppend(*aDirectory, idbDirectoryName));
QM_TRY( QM_TRY(QM_OR_ELSE_WARN(
ToResult(idbDirectory->Create(nsIFile::DIRECTORY_TYPE, 0755)) ToResult(idbDirectory->Create(nsIFile::DIRECTORY_TYPE, 0755)),
.orElse([&idbDirectory](const nsresult rv) -> Result<Ok, nsresult> { ([&idbDirectory](const nsresult rv) -> Result<Ok, nsresult> {
if (rv == NS_ERROR_FILE_ALREADY_EXISTS) { if (rv == NS_ERROR_FILE_ALREADY_EXISTS) {
NS_WARNING("IDB directory already exists!"); QM_TRY_INSPECT(const bool& isDirectory,
MOZ_TO_RESULT_INVOKE(idbDirectory, IsDirectory));
QM_TRY_INSPECT(const bool& isDirectory, QM_TRY(OkIf(isDirectory), Err(NS_ERROR_UNEXPECTED));
MOZ_TO_RESULT_INVOKE(idbDirectory, IsDirectory));
QM_TRY(OkIf(isDirectory), Err(NS_ERROR_UNEXPECTED)); return Ok{};
}
return Ok{}; return Err(rv);
} })));
return Err(rv);
}));
QM_TRY(CollectEachFile( QM_TRY(CollectEachFile(
*aDirectory, *aDirectory,

Просмотреть файл

@ -164,27 +164,26 @@ Result<nsCOMPtr<nsIFile>, nsresult> CloneFileAndAppend(
} }
Result<nsIFileKind, nsresult> GetDirEntryKind(nsIFile& aFile) { Result<nsIFileKind, nsresult> GetDirEntryKind(nsIFile& aFile) {
QM_TRY_RETURN( QM_TRY_RETURN(QM_OR_ELSE_WARN(
MOZ_TO_RESULT_INVOKE(aFile, IsDirectory) MOZ_TO_RESULT_INVOKE(aFile, IsDirectory).map([](const bool isDirectory) {
.map([](const bool isDirectory) { return isDirectory ? nsIFileKind::ExistsAsDirectory
return isDirectory ? nsIFileKind::ExistsAsDirectory : nsIFileKind::ExistsAsFile;
: nsIFileKind::ExistsAsFile; }),
}) ([](const nsresult rv) -> Result<nsIFileKind, nsresult> {
.orElse([](const nsresult rv) -> Result<nsIFileKind, nsresult> { if (rv == NS_ERROR_FILE_NOT_FOUND ||
if (rv == NS_ERROR_FILE_NOT_FOUND || rv == NS_ERROR_FILE_TARGET_DOES_NOT_EXIST
rv == NS_ERROR_FILE_TARGET_DOES_NOT_EXIST
#ifdef WIN32 #ifdef WIN32
// We treat ERROR_FILE_CORRUPT as if the file did not exist at // We treat ERROR_FILE_CORRUPT as if the file did not exist at
// all. // all.
|| (NS_ERROR_GET_MODULE(rv) == NS_ERROR_MODULE_WIN32 && || (NS_ERROR_GET_MODULE(rv) == NS_ERROR_MODULE_WIN32 &&
NS_ERROR_GET_CODE(rv) == ERROR_FILE_CORRUPT) NS_ERROR_GET_CODE(rv) == ERROR_FILE_CORRUPT)
#endif #endif
) { ) {
return nsIFileKind::DoesNotExist; return nsIFileKind::DoesNotExist;
} }
return Err(rv); return Err(rv);
})); })));
} }
Result<nsCOMPtr<mozIStorageStatement>, nsresult> CreateStatement( Result<nsCOMPtr<mozIStorageStatement>, nsresult> CreateStatement(
@ -348,9 +347,9 @@ nsDependentCSubstring MakeRelativeSourceFileName(
} // namespace detail } // namespace detail
void LogError(const nsACString& aExpr, const nsACString& aSourceFile, void LogError(const nsACString& aExpr, const Maybe<nsresult> aRv,
const int32_t aSourceLine, const Maybe<nsresult> aRv, const nsACString& aSourceFile, const int32_t aSourceLine,
const bool aIsWarning) { const Severity aSeverity) {
#if defined(EARLY_BETA_OR_EARLIER) || defined(DEBUG) #if defined(EARLY_BETA_OR_EARLIER) || defined(DEBUG)
nsAutoCString extraInfosString; nsAutoCString extraInfosString;
@ -371,6 +370,18 @@ void LogError(const nsACString& aExpr, const nsACString& aSourceFile,
const auto relativeSourceFile = const auto relativeSourceFile =
detail::MakeRelativeSourceFileName(aSourceFile); detail::MakeRelativeSourceFileName(aSourceFile);
const auto severityString = [&aSeverity]() -> nsLiteralCString {
switch (aSeverity) {
case Severity::Error:
return "ERROR"_ns;
case Severity::Warning:
return "WARNING"_ns;
case Severity::Note:
return "NOTE"_ns;
}
MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Bad severity value!");
}();
#endif #endif
#ifdef QM_ENABLE_SCOPED_LOG_EXTRA_INFO #ifdef QM_ENABLE_SCOPED_LOG_EXTRA_INFO
@ -382,20 +393,22 @@ void LogError(const nsACString& aExpr, const nsACString& aSourceFile,
#endif #endif
#ifdef DEBUG #ifdef DEBUG
NS_DebugBreak(NS_DEBUG_WARNING, nsAutoCString("QM_TRY failure"_ns).get(), NS_DebugBreak(
(extraInfosString.IsEmpty() NS_DEBUG_WARNING,
? nsPromiseFlatCString(aExpr) nsAutoCString("QM_TRY failure ("_ns + severityString + ")"_ns).get(),
: static_cast<const nsCString&>( (extraInfosString.IsEmpty() ? nsPromiseFlatCString(aExpr)
nsAutoCString(aExpr + extraInfosString))) : static_cast<const nsCString&>(nsAutoCString(
.get(), aExpr + extraInfosString)))
nsPromiseFlatCString(relativeSourceFile).get(), aSourceLine); .get(),
nsPromiseFlatCString(relativeSourceFile).get(), aSourceLine);
#endif #endif
#if defined(EARLY_BETA_OR_EARLIER) || defined(DEBUG) #if defined(EARLY_BETA_OR_EARLIER) || defined(DEBUG)
nsCOMPtr<nsIConsoleService> console = nsCOMPtr<nsIConsoleService> console =
do_GetService(NS_CONSOLESERVICE_CONTRACTID); do_GetService(NS_CONSOLESERVICE_CONTRACTID);
if (console) { if (console) {
NS_ConvertUTF8toUTF16 message("QM_TRY failure: '"_ns + aExpr + "' at "_ns + NS_ConvertUTF8toUTF16 message("QM_TRY failure ("_ns + severityString +
")"_ns + ": '"_ns + aExpr + "' at "_ns +
relativeSourceFile + ":"_ns + relativeSourceFile + ":"_ns +
IntToCString(aSourceLine) + extraInfosString); IntToCString(aSourceLine) + extraInfosString);
@ -423,8 +436,7 @@ void LogError(const nsACString& aExpr, const nsACString& aSourceFile,
EventExtraEntry{"source_line"_ns, IntToCString(aSourceLine)}); EventExtraEntry{"source_line"_ns, IntToCString(aSourceLine)});
res.AppendElement(EventExtraEntry{ res.AppendElement(EventExtraEntry{
"context"_ns, nsPromiseFlatCString{*contextIt->second}}); "context"_ns, nsPromiseFlatCString{*contextIt->second}});
res.AppendElement(EventExtraEntry{ res.AppendElement(EventExtraEntry{"severity"_ns, severityString});
"severity"_ns, aIsWarning ? "WARNING"_ns : "ERROR"_ns});
if (!rvName.IsEmpty()) { if (!rvName.IsEmpty()) {
res.AppendElement(EventExtraEntry{"result"_ns, nsCString{rvName}}); res.AppendElement(EventExtraEntry{"result"_ns, nsCString{rvName}});

Просмотреть файл

@ -447,11 +447,31 @@ class NotNull;
} while (0) } while (0)
#ifdef DEBUG #ifdef DEBUG
# define QM_HANDLE_ERROR(expr, error) \ # define QM_HANDLE_ERROR(expr, error, severity) \
HandleError(#expr, error, __FILE__, __LINE__) HandleError(#expr, error, __FILE__, __LINE__, severity)
#else #else
# define QM_HANDLE_ERROR(expr, error) \ # define QM_HANDLE_ERROR(expr, error, severity) \
HandleError("Unavailable", error, __FILE__, __LINE__) HandleError("Unavailable", error, __FILE__, __LINE__, severity)
#endif
#ifdef DEBUG
# define QM_HANDLE_ERROR_RETURN_NOTHING(expr, error, severity) \
HandleErrorReturnNothing(#expr, error, __FILE__, __LINE__, severity)
#else
# define QM_HANDLE_ERROR_RETURN_NOTHING(expr, error, severity) \
HandleErrorReturnNothing("Unavailable", error, __FILE__, __LINE__, severity)
#endif
#ifdef DEBUG
# define QM_HANDLE_ERROR_WITH_CLEANUP_RETURN_NOTHING(expr, error, severity, \
cleanup) \
HandleErrorWithCleanupReturnNothing(#expr, error, __FILE__, __LINE__, \
severity, cleanup)
#else
# define QM_HANDLE_ERROR_WITH_CLEANUP_RETURN_NOTHING(expr, error, severity, \
cleanup) \
HandleErrorWithCleanupReturnNothing("Unavailable", error, __FILE__, \
__LINE__, severity, cleanup)
#endif #endif
// QM_TRY_PROPAGATE_ERR, QM_TRY_CUSTOM_RET_VAL, // QM_TRY_PROPAGATE_ERR, QM_TRY_CUSTOM_RET_VAL,
@ -463,7 +483,8 @@ class NotNull;
auto tryResult = ::mozilla::ToResult(expr); \ auto tryResult = ::mozilla::ToResult(expr); \
static_assert(std::is_empty_v<typename decltype(tryResult)::ok_type>); \ static_assert(std::is_empty_v<typename decltype(tryResult)::ok_type>); \
if (MOZ_UNLIKELY(tryResult.isErr())) { \ if (MOZ_UNLIKELY(tryResult.isErr())) { \
ns::QM_HANDLE_ERROR(expr, tryResult.inspectErr()); \ ns::QM_HANDLE_ERROR(expr, tryResult.inspectErr(), \
mozilla::dom::quota::Severity::Error); \
return tryResult.propagateErr(); \ return tryResult.propagateErr(); \
} }
@ -474,7 +495,8 @@ class NotNull;
static_assert(std::is_empty_v<typename decltype(tryResult)::ok_type>); \ static_assert(std::is_empty_v<typename decltype(tryResult)::ok_type>); \
if (MOZ_UNLIKELY(tryResult.isErr())) { \ if (MOZ_UNLIKELY(tryResult.isErr())) { \
auto tryTempError MOZ_MAYBE_UNUSED = tryResult.unwrapErr(); \ auto tryTempError MOZ_MAYBE_UNUSED = tryResult.unwrapErr(); \
ns::QM_HANDLE_ERROR(expr, tryTempError); \ ns::QM_HANDLE_ERROR(expr, tryTempError, \
mozilla::dom::quota::Severity::Error); \
return customRetVal; \ return customRetVal; \
} }
@ -486,7 +508,8 @@ class NotNull;
static_assert(std::is_empty_v<typename decltype(tryResult)::ok_type>); \ static_assert(std::is_empty_v<typename decltype(tryResult)::ok_type>); \
if (MOZ_UNLIKELY(tryResult.isErr())) { \ if (MOZ_UNLIKELY(tryResult.isErr())) { \
auto tryTempError = tryResult.unwrapErr(); \ auto tryTempError = tryResult.unwrapErr(); \
ns::QM_HANDLE_ERROR(expr, tryTempError); \ ns::QM_HANDLE_ERROR(expr, tryTempError, \
mozilla::dom::quota::Severity::Error); \
cleanup(tryTempError); \ cleanup(tryTempError); \
return customRetVal; \ return customRetVal; \
} }
@ -513,8 +536,8 @@ class NotNull;
/** /**
* QM_TRY(expr[, customRetVal, cleanup]) is the C++ equivalent of Rust's * QM_TRY(expr[, customRetVal, cleanup]) is the C++ equivalent of Rust's
* `try!(expr);`. First, it evaluates expr, which must produce a Result value. * `try!(expr);`. First, it evaluates expr, which must produce a Result value
* On success, it discards the result altogether. On error, it calls * with empty ok_type. On Success, it does nothing else. On error, it calls
* HandleError and an additional cleanup function (if the third argument was * HandleError and an additional cleanup function (if the third argument was
* passed) and finally returns an error Result from the enclosing function or a * passed) and finally returns an error Result from the enclosing function or a
* custom return value (if the second argument was passed). * custom return value (if the second argument was passed).
@ -531,7 +554,8 @@ class NotNull;
expr) \ expr) \
auto tryResult = (expr); \ auto tryResult = (expr); \
if (MOZ_UNLIKELY(tryResult.isErr())) { \ if (MOZ_UNLIKELY(tryResult.isErr())) { \
ns::QM_HANDLE_ERROR(expr, tryResult.inspectErr()); \ ns::QM_HANDLE_ERROR(expr, tryResult.inspectErr(), \
mozilla::dom::quota::Severity::Error); \
return tryResult.propagateErr(); \ return tryResult.propagateErr(); \
} \ } \
MOZ_REMOVE_PAREN(target) = tryResult.accessFunction(); MOZ_REMOVE_PAREN(target) = tryResult.accessFunction();
@ -543,7 +567,8 @@ class NotNull;
auto tryResult = (expr); \ auto tryResult = (expr); \
if (MOZ_UNLIKELY(tryResult.isErr())) { \ if (MOZ_UNLIKELY(tryResult.isErr())) { \
auto tryTempError MOZ_MAYBE_UNUSED = tryResult.unwrapErr(); \ auto tryTempError MOZ_MAYBE_UNUSED = tryResult.unwrapErr(); \
ns::QM_HANDLE_ERROR(expr, tryTempError); \ ns::QM_HANDLE_ERROR(expr, tryTempError, \
mozilla::dom::quota::Severity::Error); \
return customRetVal; \ return customRetVal; \
} \ } \
MOZ_REMOVE_PAREN(target) = tryResult.accessFunction(); MOZ_REMOVE_PAREN(target) = tryResult.accessFunction();
@ -555,7 +580,8 @@ class NotNull;
auto tryResult = (expr); \ auto tryResult = (expr); \
if (MOZ_UNLIKELY(tryResult.isErr())) { \ if (MOZ_UNLIKELY(tryResult.isErr())) { \
auto tryTempError = tryResult.unwrapErr(); \ auto tryTempError = tryResult.unwrapErr(); \
ns::QM_HANDLE_ERROR(expr, tryTempError); \ ns::QM_HANDLE_ERROR(expr, tryTempError, \
mozilla::dom::quota::Severity::Error); \
cleanup(tryTempError); \ cleanup(tryTempError); \
return customRetVal; \ return customRetVal; \
} \ } \
@ -612,11 +638,12 @@ class NotNull;
// Note that this deliberately uses a single return statement without going // Note that this deliberately uses a single return statement without going
// through unwrap/unwrapErr/propagateErr, so that this does not prevent NRVO or // through unwrap/unwrapErr/propagateErr, so that this does not prevent NRVO or
// tail call optimizations when possible. // tail call optimizations when possible.
#define QM_TRY_RETURN_PROPAGATE_ERR(ns, tryResult, expr) \ #define QM_TRY_RETURN_PROPAGATE_ERR(ns, tryResult, expr) \
auto tryResult = ::mozilla::ToResult(expr); \ auto tryResult = ::mozilla::ToResult(expr); \
if (MOZ_UNLIKELY(tryResult.isErr())) { \ if (MOZ_UNLIKELY(tryResult.isErr())) { \
ns::QM_HANDLE_ERROR(expr, tryResult.inspectErr()); \ ns::QM_HANDLE_ERROR(expr, tryResult.inspectErr(), \
} \ mozilla::dom::quota::Severity::Error); \
} \
return tryResult; return tryResult;
// Handles the four arguments case when a custom return value needs to be // Handles the four arguments case when a custom return value needs to be
@ -625,7 +652,8 @@ class NotNull;
auto tryResult = ::mozilla::ToResult(expr); \ auto tryResult = ::mozilla::ToResult(expr); \
if (MOZ_UNLIKELY(tryResult.isErr())) { \ if (MOZ_UNLIKELY(tryResult.isErr())) { \
auto tryTempError MOZ_MAYBE_UNUSED = tryResult.unwrapErr(); \ auto tryTempError MOZ_MAYBE_UNUSED = tryResult.unwrapErr(); \
ns::QM_HANDLE_ERROR(expr, tryResult.inspectErr()); \ ns::QM_HANDLE_ERROR(expr, tryResult.inspectErr(), \
mozilla::dom::quota::Severity::Error); \
return customRetVal; \ return customRetVal; \
} \ } \
return tryResult.unwrap(); return tryResult.unwrap();
@ -637,7 +665,8 @@ class NotNull;
auto tryResult = ::mozilla::ToResult(expr); \ auto tryResult = ::mozilla::ToResult(expr); \
if (MOZ_UNLIKELY(tryResult.isErr())) { \ if (MOZ_UNLIKELY(tryResult.isErr())) { \
auto tryTempError = tryResult.unwrapErr(); \ auto tryTempError = tryResult.unwrapErr(); \
ns::QM_HANDLE_ERROR(expr, tryTempError); \ ns::QM_HANDLE_ERROR(expr, tryTempError, \
mozilla::dom::quota::Severity::Error); \
cleanup(tryTempError); \ cleanup(tryTempError); \
return customRetVal; \ return customRetVal; \
} \ } \
@ -675,15 +704,15 @@ class NotNull;
// details of QM_FAIL and shouldn't be used directly. // details of QM_FAIL and shouldn't be used directly.
// Handles the two arguments case when just an error is returned // Handles the two arguments case when just an error is returned
#define QM_FAIL_RET_VAL(ns, retVal) \ #define QM_FAIL_RET_VAL(ns, retVal) \
ns::QM_HANDLE_ERROR(Failure, 0); \ ns::QM_HANDLE_ERROR(Failure, 0, mozilla::dom::quota::Severity::Error); \
return retVal; return retVal;
// Handles the three arguments case when a cleanup function needs to be called // Handles the three arguments case when a cleanup function needs to be called
// before a return value is returned // before a return value is returned
#define QM_FAIL_RET_VAL_WITH_CLEANUP(ns, retVal, cleanup) \ #define QM_FAIL_RET_VAL_WITH_CLEANUP(ns, retVal, cleanup) \
ns::QM_HANDLE_ERROR(Failure, 0); \ ns::QM_HANDLE_ERROR(Failure, 0, mozilla::dom::quota::Severity::Error); \
cleanup(); \ cleanup(); \
return retVal; return retVal;
// Chooses the final implementation macro for given argument count. // Chooses the final implementation macro for given argument count.
@ -703,6 +732,159 @@ class NotNull;
*/ */
#define QM_FAIL(...) QM_FAIL_GLUE(__VA_ARGS__) #define QM_FAIL(...) QM_FAIL_GLUE(__VA_ARGS__)
// QM_REPORTONLY_TRY, QM_REPORTONLY_TRY_WITH_CLEANUP, QM_REPORTONLY_TRY_GLUE
// macros are implementation details of QM_WARNONLY_TRY/QM_NOTEONLY_TRY and
// shouldn't be used directly.
// Handles the four arguments case when only a warning/note is reported.
#define QM_REPORTONLY_TRY(ns, tryResult, severity, expr) \
auto tryResult = ::mozilla::ToResult(expr); \
static_assert(std::is_empty_v<typename decltype(tryResult)::ok_type>); \
if (MOZ_UNLIKELY(tryResult.isErr())) { \
ns::QM_HANDLE_ERROR(expr, tryResult.unwrapErr(), \
mozilla::dom::quota::Severity::severity); \
}
// Handles the five arguments case when a cleanup function needs to be called
#define QM_REPORTONLY_TRY_WITH_CLEANUP(ns, tryResult, severity, expr, cleanup) \
auto tryResult = ::mozilla::ToResult(expr); \
static_assert(std::is_empty_v<typename decltype(tryResult)::ok_type>); \
if (MOZ_UNLIKELY(tryResult.isErr())) { \
auto tryTempError = tryResult.unwrapErr(); \
ns::QM_HANDLE_ERROR(expr, tryTempError, \
mozilla::dom::quota::Severity::severity); \
cleanup(tryTempError); \
}
// Chooses the final implementation macro for given argument count.
// It can be used by other modules to define module specific error handling.
// See also the comment for QM_TRY_META.
#define QM_REPORTONLY_TRY_META(...) \
{ \
MOZ_ARG_7(, ##__VA_ARGS__, QM_REPORTONLY_TRY_WITH_CLEANUP(__VA_ARGS__), \
QM_REPORTONLY_TRY(__VA_ARGS__), QM_MISSING_ARGS(__VA_ARGS__), \
QM_MISSING_ARGS(__VA_ARGS__), QM_MISSING_ARGS(__VA_ARGS__), \
QM_MISSING_ARGS(__VA_ARGS__)) \
}
// Specifies the namespace and generates unique variable name. This extra
// internal macro (along with __COUNTER__) allows nesting of the final macro.
#define QM_REPORTONLY_TRY_GLUE(severity, ...) \
QM_REPORTONLY_TRY_META(mozilla::dom::quota, MOZ_UNIQUE_VAR(tryResult), \
severity, ##__VA_ARGS__)
/**
* QM_WARNONLY_TRY(expr[, cleanup]) evaluates expr, which must produce a
* Result value with empty ok_type. On Success, it does nothing else. On error,
* it calls HandleError and an additional cleanup function (if the second
* argument was passed). This macro never returns and failures are always
* reported using a lower level of severity relative to failures reported by
* QM_TRY. The macro is intended for failures that should not be propagated.
*/
#define QM_WARNONLY_TRY(...) QM_REPORTONLY_TRY_GLUE(Warning, __VA_ARGS__)
/**
* QM_NOTEONLY_TRY is like QM_WARNONLY_TRY. The only difference is that
* failures are reported using a lower level of severity relative to failures
* reported by QM_WARNONLY_TRY.
*/
#define QM_NOTEONLY_TRY(...) QM_REPORTONLY_TRY_GLUE(Note, __VA_ARGS__)
// QM_REPORTONLY_TRY_ASSIGN, QM_REPORTONLY_TRY_ASSIGN_WITH_CLEANUP,
// QM_REPORTONLY_TRY_ASSIGN_GLUE macros are implementation details of
// QM_WARNONLY_TRY_UNWRAP/QM_NOTEONLY_TRY_UNWRAP and shouldn't be used
// directly.
// Handles the five arguments case when only a warning/note is reported.
#define QM_REPORTONLY_TRY_ASSIGN(ns, tryResult, severity, target, expr) \
auto tryResult = (expr); \
MOZ_REMOVE_PAREN(target) = \
MOZ_LIKELY(tryResult.isOk()) \
? Some(tryResult.unwrap()) \
: ns::QM_HANDLE_ERROR_RETURN_NOTHING( \
expr, tryResult.unwrapErr(), \
mozilla::dom::quota::Severity::severity);
// Handles the six arguments case when a cleanup function needs to be called
#define QM_REPORTONLY_TRY_ASSIGN_WITH_CLEANUP(ns, tryResult, severity, target, \
expr, cleanup) \
auto tryResult = (expr); \
MOZ_REMOVE_PAREN(target) = \
MOZ_LIKELY(tryResult.isOk()) \
? Some(tryResult.unwrap()) \
: ns::QM_HANDLE_ERROR_WITH_CLEANUP_RETURN_NOTHING( \
expr, tryResult.unwrapErr(), \
mozilla::dom::quota::Severity::severity, cleanup);
// Chooses the final implementation macro for given argument count.
// It can be used by other modules to define module specific error handling.
// See also the comment for QM_TRY_META.
#define QM_REPORTONLY_TRY_ASSIGN_META(...) \
MOZ_ARG_8( \
, ##__VA_ARGS__, QM_REPORTONLY_TRY_ASSIGN_WITH_CLEANUP(__VA_ARGS__), \
QM_REPORTONLY_TRY_ASSIGN(__VA_ARGS__), QM_MISSING_ARGS(__VA_ARGS__), \
QM_MISSING_ARGS(__VA_ARGS__), QM_MISSING_ARGS(__VA_ARGS__), \
QM_MISSING_ARGS(__VA_ARGS__), QM_MISSING_ARGS(__VA_ARGS__))
// Specifies the namespace and generates unique variable name. This extra
// internal macro (along with __COUNTER__) allows nesting of the final macro.
#define QM_REPORTONLY_TRY_ASSIGN_GLUE(severity, ...) \
QM_REPORTONLY_TRY_ASSIGN_META( \
mozilla::dom::quota, MOZ_UNIQUE_VAR(tryResult), severity, ##__VA_ARGS__)
/**
* QM_WARNONLY_TRY_UNWRAP(target, expr[, cleanup]) evaluates expr, which must
* produce a Result value. On success, the result's success value is first
* unwrapped from the Result, then wrapped in a Maybe and finally assigned to
* target. On error, it calls HandleError and an additional cleanup
* function (if the third argument was passed) and finally assigns Nothing to
* target. |target| must be an lvalue. This macro never returns and failures
* are always reported using a lower level of severity relative to failures
* reported by QM_TRY_UNWRAP/QM_TRY_INSPECT. The macro is intended for failures
* that should not be propagated.
*/
#define QM_WARNONLY_TRY_UNWRAP(...) \
QM_REPORTONLY_TRY_ASSIGN_GLUE(Warning, __VA_ARGS__)
// QM_WARNONLY_TRY_INSPECT doesn't make sense.
/**
* QM_NOTEONLY_TRY_UNWRAP is like QM_WARN_CHECK_UNWRAP. The only difference is
* that failures are reported using a lower level of severity relative to
* failures reported by QM_WARN_CHECK_UNWRAP.
*/
#define QM_NOTEONLY_TRY_UNWRAP(...) \
QM_REPORTONLY_TRY_ASSIGN_GLUE(Note, __VA_ARGS__)
// QM_NOTEONLY_TRY_INSPECT doesn't make sense.
/*
* QM_OR_ELSE_WARN(expr, orElse) evaluates expr, which must produce a Result
* value. On Success, it just moves the success over. On error, it calls
* HandleError and a custom orElse function (passed as the second argument).
* Failures are always reported as warnings. The macro essentially wraps the
* orElse function with a warning. The macro is a sub macro and is intended to
* be used along with one of the main macros such as QM_TRY.
*/
#define QM_OR_ELSE_WARN(expr, orElseFunc) \
(expr).orElse([&](const auto& firstRes) { \
mozilla::dom::quota::QM_HANDLE_ERROR( \
#expr, firstRes, mozilla::dom::quota::Severity::Warning); \
return orElseFunc(firstRes); \
})
/**
* QM_OR_ELSE_NOTE is like QM_OR_ELSE_WARN. The only difference is that
* failures are reported using a lower level of severity relative to failures
* reported by QM_OR_ELSE_WARN.
*/
#define QM_OR_ELSE_NOTE(expr, orElseFunc) \
(expr).orElse([&](const auto& firstRes) { \
mozilla::dom::quota::QM_HANDLE_ERROR(#expr, firstRes, \
mozilla::dom::quota::Severity::Note); \
return orElseFunc(firstRes); \
})
// Telemetry probes to collect number of failure during the initialization. // Telemetry probes to collect number of failure during the initialization.
#ifdef NIGHTLY_BUILD #ifdef NIGHTLY_BUILD
# define RECORD_IN_NIGHTLY(_recorder, _status) \ # define RECORD_IN_NIGHTLY(_recorder, _status) \
@ -760,7 +942,7 @@ auto ErrToOkOrErr(nsresult aValue) -> Result<V, nsresult> {
return Err(aValue); return Err(aValue);
} }
template <nsresult ErrorValue, typename V> template <nsresult ErrorValue, typename V = mozilla::Ok>
auto ErrToDefaultOkOrErr(nsresult aValue) -> Result<V, nsresult> { auto ErrToDefaultOkOrErr(nsresult aValue) -> Result<V, nsresult> {
if (aValue == ErrorValue) { if (aValue == ErrorValue) {
return V{}; return V{};
@ -1016,9 +1198,15 @@ nsDependentCSubstring MakeRelativeSourceFileName(const nsACString& aSourceFile);
} // namespace detail } // namespace detail
void LogError(const nsACString& aExpr, const nsACString& aSourceFile, enum class Severity {
int32_t aSourceLine, Maybe<nsresult> aRv, Error,
bool aIsWarning = false); Warning,
Note,
};
void LogError(const nsACString& aExpr, Maybe<nsresult> aRv,
const nsACString& aSourceFile, int32_t aSourceLine,
Severity aSeverity);
#ifdef DEBUG #ifdef DEBUG
Result<bool, nsresult> WarnIfFileIsUnknown(nsIFile& aFile, Result<bool, nsresult> WarnIfFileIsUnknown(nsIFile& aFile,
@ -1096,24 +1284,45 @@ struct MOZ_STACK_CLASS ScopedLogExtraInfo {
#if defined(EARLY_BETA_OR_EARLIER) || defined(DEBUG) #if defined(EARLY_BETA_OR_EARLIER) || defined(DEBUG)
template <typename T> template <typename T>
MOZ_COLD void HandleError(const char* aExpr, const T& aRv, MOZ_COLD void HandleError(const char* aExpr, const T& aRv,
const char* aSourceFile, int32_t aSourceLine) { const char* aSourceFile, int32_t aSourceLine,
const Severity aSeverity) {
if constexpr (std::is_same_v<T, nsresult>) { if constexpr (std::is_same_v<T, nsresult>) {
mozilla::dom::quota::LogError(nsDependentCString(aExpr), mozilla::dom::quota::LogError(nsDependentCString(aExpr), Some(aRv),
nsDependentCString(aSourceFile), aSourceLine, nsDependentCString(aSourceFile), aSourceLine,
Some(aRv)); aSeverity);
} else { } else {
mozilla::dom::quota::LogError(nsDependentCString(aExpr), mozilla::dom::quota::LogError(nsDependentCString(aExpr), Nothing{},
nsDependentCString(aSourceFile), aSourceLine, nsDependentCString(aSourceFile), aSourceLine,
Nothing{}); aSeverity);
} }
} }
#else #else
template <typename T> template <typename T>
MOZ_ALWAYS_INLINE constexpr void HandleError(const char* aExpr, const T& aRv, MOZ_ALWAYS_INLINE constexpr void HandleError(const char* aExpr, const T& aRv,
const char* aSourceFile, const char* aSourceFile,
int32_t aSourceLine) {} int32_t aSourceLine,
const Severity aSeverity) {}
#endif #endif
template <typename T>
Nothing HandleErrorReturnNothing(const char* aExpr, const T& aRv,
const char* aSourceFile, int32_t aSourceLine,
const Severity aSeverity) {
HandleError(aExpr, aRv, aSourceFile, aSourceLine, aSeverity);
return Nothing();
}
template <typename T, typename CleanupFunc>
Nothing HandleErrorWithCleanupReturnNothing(const char* aExpr, const T& aRv,
const char* aSourceFile,
int32_t aSourceLine,
const Severity aSeverity,
CleanupFunc&& aCleanupFunc) {
HandleError(aExpr, aRv, aSourceFile, aSourceLine, aSeverity);
std::forward<CleanupFunc>(aCleanupFunc)(aRv);
return Nothing();
}
template <SingleStepResult ResultHandling = SingleStepResult::AssertHasResult, template <SingleStepResult ResultHandling = SingleStepResult::AssertHasResult,
typename BindFunctor> typename BindFunctor>
Result<SingleStepSuccessType<ResultHandling>, nsresult> Result<SingleStepSuccessType<ResultHandling>, nsresult>

Просмотреть файл

@ -1022,6 +1022,228 @@ TEST(QuotaCommon_Fail, ReturnValue_WithCleanup)
EXPECT_EQ(rv, NS_ERROR_FAILURE); EXPECT_EQ(rv, NS_ERROR_FAILURE);
} }
TEST(QuotaCommon_WarnOnlyTry, Success)
{
bool warnOnlyTryDidNotReturn = false;
const auto res =
[&warnOnlyTryDidNotReturn]() -> mozilla::Result<mozilla::Ok, NotOk> {
QM_WARNONLY_TRY(OkIf(true));
warnOnlyTryDidNotReturn = true;
return mozilla::Ok{};
}();
EXPECT_TRUE(res.isOk());
EXPECT_TRUE(warnOnlyTryDidNotReturn);
}
TEST(QuotaCommon_WarnOnlyTry, Success_WithCleanup)
{
bool warnOnlyTryCleanupRan = false;
bool warnOnlyTryDidNotReturn = false;
const auto res =
[&warnOnlyTryCleanupRan,
&warnOnlyTryDidNotReturn]() -> mozilla::Result<mozilla::Ok, NotOk> {
QM_WARNONLY_TRY(OkIf(true), [&warnOnlyTryCleanupRan](const auto&) {
warnOnlyTryCleanupRan = true;
});
warnOnlyTryDidNotReturn = true;
return mozilla::Ok{};
}();
EXPECT_TRUE(res.isOk());
EXPECT_FALSE(warnOnlyTryCleanupRan);
EXPECT_TRUE(warnOnlyTryDidNotReturn);
}
TEST(QuotaCommon_WarnOnlyTry, Failure)
{
bool warnOnlyTryDidNotReturn = false;
const auto res =
[&warnOnlyTryDidNotReturn]() -> mozilla::Result<mozilla::Ok, NotOk> {
QM_WARNONLY_TRY(OkIf(false));
warnOnlyTryDidNotReturn = true;
return mozilla::Ok{};
}();
EXPECT_TRUE(res.isOk());
EXPECT_TRUE(warnOnlyTryDidNotReturn);
}
TEST(QuotaCommon_WarnOnlyTry, Failure_WithCleanup)
{
bool warnOnlyTryCleanupRan = false;
bool warnOnlyTryDidNotReturn = false;
const auto res =
[&warnOnlyTryCleanupRan,
&warnOnlyTryDidNotReturn]() -> mozilla::Result<mozilla::Ok, NotOk> {
QM_WARNONLY_TRY(OkIf(false), ([&warnOnlyTryCleanupRan](const auto&) {
warnOnlyTryCleanupRan = true;
}));
warnOnlyTryDidNotReturn = true;
return mozilla::Ok{};
}();
EXPECT_TRUE(res.isOk());
EXPECT_TRUE(warnOnlyTryCleanupRan);
EXPECT_TRUE(warnOnlyTryDidNotReturn);
}
TEST(QuotaCommon_WarnOnlyTryUnwrap, Success)
{
bool warnOnlyTryUnwrapDidNotReturn = false;
const auto res = [&warnOnlyTryUnwrapDidNotReturn]()
-> mozilla::Result<mozilla::Ok, NotOk> {
QM_WARNONLY_TRY_UNWRAP(const auto x, (Result<int32_t, NotOk>{42}));
EXPECT_TRUE(x);
EXPECT_EQ(*x, 42);
warnOnlyTryUnwrapDidNotReturn = true;
return mozilla::Ok{};
}();
EXPECT_TRUE(res.isOk());
EXPECT_TRUE(warnOnlyTryUnwrapDidNotReturn);
}
TEST(QuotaCommon_WarnOnlyTryUnwrap, Success_WithCleanup)
{
bool warnOnlyTryUnwrapCleanupRan = false;
bool warnOnlyTryUnwrapDidNotReturn = false;
const auto res = [&warnOnlyTryUnwrapCleanupRan,
&warnOnlyTryUnwrapDidNotReturn]()
-> mozilla::Result<mozilla::Ok, NotOk> {
QM_WARNONLY_TRY_UNWRAP(const auto x, (Result<int32_t, NotOk>{42}),
[&warnOnlyTryUnwrapCleanupRan](const auto&) {
warnOnlyTryUnwrapCleanupRan = true;
});
EXPECT_TRUE(x);
EXPECT_EQ(*x, 42);
warnOnlyTryUnwrapDidNotReturn = true;
return mozilla::Ok{};
}();
EXPECT_TRUE(res.isOk());
EXPECT_FALSE(warnOnlyTryUnwrapCleanupRan);
EXPECT_TRUE(warnOnlyTryUnwrapDidNotReturn);
}
TEST(QuotaCommon_WarnOnlyTryUnwrap, Failure)
{
bool warnOnlyTryUnwrapDidNotReturn = false;
const auto res = [&warnOnlyTryUnwrapDidNotReturn]()
-> mozilla::Result<mozilla::Ok, NotOk> {
QM_WARNONLY_TRY_UNWRAP(const auto x,
(Result<int32_t, NotOk>{Err(NotOk{})}));
EXPECT_FALSE(x);
warnOnlyTryUnwrapDidNotReturn = true;
return mozilla::Ok{};
}();
EXPECT_TRUE(res.isOk());
EXPECT_TRUE(warnOnlyTryUnwrapDidNotReturn);
}
TEST(QuotaCommon_WarnOnlyTryUnwrap, Failure_WithCleanup)
{
bool warnOnlyTryUnwrapCleanupRan = false;
bool warnOnlyTryUnwrapDidNotReturn = false;
const auto res = [&warnOnlyTryUnwrapCleanupRan,
&warnOnlyTryUnwrapDidNotReturn]()
-> mozilla::Result<mozilla::Ok, NotOk> {
QM_WARNONLY_TRY_UNWRAP(const auto x, (Result<int32_t, NotOk>{Err(NotOk{})}),
[&warnOnlyTryUnwrapCleanupRan](const auto&) {
warnOnlyTryUnwrapCleanupRan = true;
});
EXPECT_FALSE(x);
warnOnlyTryUnwrapDidNotReturn = true;
return mozilla::Ok{};
}();
EXPECT_TRUE(res.isOk());
EXPECT_TRUE(warnOnlyTryUnwrapCleanupRan);
EXPECT_TRUE(warnOnlyTryUnwrapDidNotReturn);
}
TEST(QuotaCommon_OrElseWarn, Success)
{
bool orElseWarnRun = false;
bool tryContinued = false;
const auto res = [&]() -> mozilla::Result<mozilla::Ok, NotOk> {
QM_TRY(QM_OR_ELSE_WARN(OkIf(true), ([&orElseWarnRun](const NotOk) {
orElseWarnRun = true;
return mozilla::Result<mozilla::Ok, NotOk>{
mozilla::Ok{}};
})));
tryContinued = true;
return mozilla::Ok{};
}();
EXPECT_TRUE(res.isOk());
EXPECT_FALSE(orElseWarnRun);
EXPECT_TRUE(tryContinued);
}
TEST(QuotaCommon_OrElseWarn, Failure_MappedToSuccess)
{
bool orElseWarnRun = false;
bool tryContinued = false;
// XXX Consider allowing to set a custom error handler, so that we can
// actually assert that a warning was emitted.
const auto res = [&]() -> mozilla::Result<mozilla::Ok, NotOk> {
QM_TRY(QM_OR_ELSE_WARN(OkIf(false), ([&orElseWarnRun](const NotOk) {
orElseWarnRun = true;
return mozilla::Result<mozilla::Ok, NotOk>{
mozilla::Ok{}};
})));
tryContinued = true;
return mozilla::Ok{};
}();
EXPECT_TRUE(res.isOk());
EXPECT_TRUE(orElseWarnRun);
EXPECT_TRUE(tryContinued);
}
TEST(QuotaCommon_OrElseWarn, Failure_MappedToError)
{
bool orElseWarnRun = false;
bool tryContinued = false;
// XXX Consider allowing to set a custom error handler, so that we can
// actually assert that a warning was emitted.
const auto res = [&]() -> mozilla::Result<mozilla::Ok, NotOk> {
QM_TRY(QM_OR_ELSE_WARN(OkIf(false), ([&orElseWarnRun](const NotOk) {
orElseWarnRun = true;
return mozilla::Result<mozilla::Ok, NotOk>{
NotOk{}};
})));
tryContinued = true;
return mozilla::Ok{};
}();
EXPECT_TRUE(res.isErr());
EXPECT_TRUE(orElseWarnRun);
EXPECT_FALSE(tryContinued);
}
TEST(QuotaCommon_OkIf, True) TEST(QuotaCommon_OkIf, True)
{ {
auto res = OkIf(true); auto res = OkIf(true);