зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
1b4f665f90
Коммит
6edcf204fd
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) ||
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче