зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1481819 - Make Safe Browsing directory-based file copy interruptible. r=francois
A directory-based file copy without checkpoint to abort may take lots of time to finish. This cause an issue that if firefox is shutting down and try to close an ongoing update thread, main-thread may be blocked for a long time. This patch adds a wrapper for copying an entire directory, within this wrapper, we use file-based copy and add checkpoints to let update thread has a chance to abort. Differential Revision: https://phabricator.services.mozilla.com/D3414 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
926304f225
Коммит
e05a4185a6
|
@ -794,16 +794,12 @@ Classifier::ApplyUpdatesBackground(TableUpdateArray& aUpdates,
|
|||
|
||||
nsresult rv;
|
||||
|
||||
// Check point 1: Copying file takes time so we check here.
|
||||
if (mUpdateInterrupted) {
|
||||
LOG(("Update is interrupted. Don't copy files."));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Check point 1: Copying files takes time so we check |mUpdateInterrupted|
|
||||
// inside CopyInUseDirForUpdate().
|
||||
rv = CopyInUseDirForUpdate(); // i.e. mUpdatingDirectory will be setup.
|
||||
if (NS_FAILED(rv)) {
|
||||
LOG(("Failed to copy in-use directory for update."));
|
||||
return rv;
|
||||
return (rv == NS_ERROR_ABORT) ? NS_OK : rv;
|
||||
}
|
||||
|
||||
LOG(("Applying %zu table updates.", aUpdates.Length()));
|
||||
|
@ -1096,6 +1092,64 @@ Classifier::DumpFailedUpdate()
|
|||
|
||||
#endif // MOZ_SAFEBROWSING_DUMP_FAILED_UPDATES
|
||||
|
||||
/**
|
||||
* This function copies the files one by one to the destination folder.
|
||||
* Before copying a file, it checks |mUpdateInterrupted| and returns
|
||||
* NS_ERROR_ABORT if the flag is set.
|
||||
*/
|
||||
nsresult
|
||||
Classifier::CopyDirectoryInterruptible(nsCOMPtr<nsIFile>& aDestDir, nsCOMPtr<nsIFile>& aSourceDir)
|
||||
{
|
||||
nsCOMPtr<nsIDirectoryEnumerator> entries;
|
||||
nsresult rv = aSourceDir->GetDirectoryEntries(getter_AddRefs(entries));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
MOZ_ASSERT(entries);
|
||||
|
||||
nsCOMPtr<nsIFile> source;
|
||||
while (NS_SUCCEEDED(rv = entries->GetNextFile(getter_AddRefs(source))) &&
|
||||
source) {
|
||||
if (mUpdateInterrupted) {
|
||||
LOG(("Update is interrupted. Aborting the directory copy"));
|
||||
return NS_ERROR_ABORT;
|
||||
}
|
||||
|
||||
bool isDirectory;
|
||||
rv = source->IsDirectory(&isDirectory);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (isDirectory) {
|
||||
// If it is a directory, recursively copy the files inside the directory.
|
||||
nsAutoCString leaf;
|
||||
source->GetNativeLeafName(leaf);
|
||||
MOZ_ASSERT(!leaf.IsEmpty());
|
||||
|
||||
nsCOMPtr<nsIFile> dest;
|
||||
aDestDir->Clone(getter_AddRefs(dest));
|
||||
dest->AppendNative(leaf);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = CopyDirectoryInterruptible(dest, source);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
} else {
|
||||
rv = source->CopyToNative(aDestDir, EmptyCString());
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
}
|
||||
|
||||
// If the destination directory doesn't exist in the end, it means that the
|
||||
// source directory is empty, we should copy the directory here.
|
||||
bool exist;
|
||||
rv = aDestDir->Exists(&exist);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!exist) {
|
||||
rv = aDestDir->Create(nsIFile::DIRECTORY_TYPE, 0755);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
Classifier::CopyInUseDirForUpdate()
|
||||
{
|
||||
|
@ -1104,17 +1158,15 @@ Classifier::CopyInUseDirForUpdate()
|
|||
// We copy everything from in-use directory to a temporary directory
|
||||
// for updating.
|
||||
|
||||
nsCString updatingDirName;
|
||||
nsresult rv = mUpdatingDirectory->GetNativeLeafName(updatingDirName);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Remove the destination directory first (just in case) the do the copy.
|
||||
mUpdatingDirectory->Remove(true);
|
||||
if (!mRootStoreDirectoryForUpdate) {
|
||||
LOG(("mRootStoreDirectoryForUpdate is null."));
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
rv = mRootStoreDirectoryForUpdate->CopyToNative(nullptr, updatingDirName);
|
||||
|
||||
nsresult rv = CopyDirectoryInterruptible(mUpdatingDirectory,
|
||||
mRootStoreDirectoryForUpdate);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
|
|
|
@ -134,6 +134,7 @@ private:
|
|||
nsresult RecoverBackups();
|
||||
nsresult CleanToDelete();
|
||||
nsresult CopyInUseDirForUpdate();
|
||||
nsresult CopyDirectoryInterruptible(nsCOMPtr<nsIFile>& aDestDir, nsCOMPtr<nsIFile>& aSourceDir);
|
||||
nsresult RegenActiveTables();
|
||||
|
||||
void MergeNewLookupCaches(); // Merge mNewLookupCaches into mLookupCaches.
|
||||
|
|
Загрузка…
Ссылка в новой задаче