Bug 727370 - Make SafeBrowsing updates atomic transactions. r=dcamp

This commit is contained in:
Gian-Carlo Pascutto 2012-09-28 18:31:18 +02:00
parent d661e4976a
commit 9513551d00
7 changed files with 255 additions and 214 deletions

View File

@ -1,41 +1,7 @@
//* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Url Classifier code
*
* The Initial Developer of the Original Code is
* the Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Dave Camp <dcamp@mozilla.com>
* Gian-Carlo Pascutto <gpascutto@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "Classifier.h"
#include "nsIPrefBranch.h"
@ -59,6 +25,10 @@ extern PRLogModuleInfo *gUrlClassifierDbServiceLog;
#define LOG_ENABLED() (false)
#endif
#define STORE_DIRECTORY NS_LITERAL_CSTRING("safebrowsing")
#define TO_DELETE_DIR_SUFFIX NS_LITERAL_CSTRING("-to_delete")
#define BACKUP_DIR_SUFFIX NS_LITERAL_CSTRING("-backup")
namespace mozilla {
namespace safebrowsing {
@ -144,21 +114,62 @@ Classifier::InitKey()
return NS_OK;
}
nsresult
Classifier::SetupPathNames()
{
// Get the root directory where to store all the databases.
nsresult rv = mCacheDirectory->Clone(getter_AddRefs(mStoreDirectory));
NS_ENSURE_SUCCESS(rv, rv);
rv = mStoreDirectory->AppendNative(STORE_DIRECTORY);
NS_ENSURE_SUCCESS(rv, rv);
// Make sure LookupCaches (which are persistent and survive updates)
// are reading/writing in the right place. We will be moving their
// files "underneath" them during backup/restore.
for (uint32 i = 0; i < mLookupCaches.Length(); i++) {
mLookupCaches[i]->UpdateDirHandle(mStoreDirectory);
}
// Directory where to move a backup before an update.
rv = mCacheDirectory->Clone(getter_AddRefs(mBackupDirectory));
NS_ENSURE_SUCCESS(rv, rv);
rv = mBackupDirectory->AppendNative(STORE_DIRECTORY + BACKUP_DIR_SUFFIX);
NS_ENSURE_SUCCESS(rv, rv);
// Directory where to move the backup so we can atomically
// delete (really move) it.
rv = mCacheDirectory->Clone(getter_AddRefs(mToDeleteDirectory));
NS_ENSURE_SUCCESS(rv, rv);
rv = mToDeleteDirectory->AppendNative(STORE_DIRECTORY + TO_DELETE_DIR_SUFFIX);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
nsresult
Classifier::Open(nsIFile& aCacheDirectory)
{
nsresult rv;
// Remember the Local profile directory.
nsresult rv = aCacheDirectory.Clone(getter_AddRefs(mCacheDirectory));
NS_ENSURE_SUCCESS(rv, rv);
mCryptoHash = do_CreateInstance(NS_CRYPTO_HASH_CONTRACTID, &rv);
// Create the handles to the update and backup directories.
rv = SetupPathNames();
NS_ENSURE_SUCCESS(rv, rv);
// Clean up any to-delete directories that haven't been deleted yet.
rv = CleanToDelete();
NS_ENSURE_SUCCESS(rv, rv);
// Check whether we have an incomplete update and recover from the
// backup if so.
rv = RecoverBackups();
NS_ENSURE_SUCCESS(rv, rv);
// Ensure the safebrowsing directory exists.
rv = aCacheDirectory.Clone(getter_AddRefs(mStoreDirectory));
NS_ENSURE_SUCCESS(rv, rv);
rv = mStoreDirectory->AppendNative(NS_LITERAL_CSTRING("safebrowsing"));
NS_ENSURE_SUCCESS(rv, rv);
bool storeExists;
rv = mStoreDirectory->Exists(&storeExists);
NS_ENSURE_SUCCESS(rv, rv);
@ -174,6 +185,9 @@ Classifier::Open(nsIFile& aCacheDirectory)
return NS_ERROR_FILE_DESTINATION_NOT_DIR;
}
mCryptoHash = do_CreateInstance(NS_CRYPTO_HASH_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = InitKey();
if (NS_FAILED(rv)) {
// Without a usable key the database is useless
@ -182,44 +196,31 @@ Classifier::Open(nsIFile& aCacheDirectory)
}
mTableFreshness.Init();
// Build the list of know urlclassifier lists
// XXX: Disk IO potentially on the main thread during startup
RegenActiveTables();
return NS_OK;
}
nsresult
void
Classifier::Close()
{
DropStores();
return NS_OK;
}
nsresult
void
Classifier::Reset()
{
DropStores();
nsCOMPtr<nsISimpleEnumerator> entries;
nsresult rv = mStoreDirectory->GetDirectoryEntries(getter_AddRefs(entries));
NS_ENSURE_SUCCESS(rv, rv);
bool hasMore;
while (NS_SUCCEEDED(rv = entries->HasMoreElements(&hasMore)) && hasMore) {
nsCOMPtr<nsIFile> file;
rv = entries->GetNext(getter_AddRefs(file));
NS_ENSURE_SUCCESS(rv, rv);
rv = file->Remove(false);
NS_ENSURE_SUCCESS(rv, rv);
}
NS_ENSURE_SUCCESS(rv, rv);
mStoreDirectory->Remove(true);
mBackupDirectory->Remove(true);
mToDeleteDirectory->Remove(true);
mTableFreshness.Clear();
RegenActiveTables();
return NS_OK;
}
void
@ -356,15 +357,19 @@ Classifier::ApplyUpdates(nsTArray<TableUpdate*>* aUpdates)
}
#endif
LOG(("Applying table updates."));
LOG(("Backup before update."));
nsresult rv;
nsresult rv = BackupTables();
NS_ENSURE_SUCCESS(rv, rv);
LOG(("Applying table updates."));
for (uint32 i = 0; i < aUpdates->Length(); i++) {
// Previous ApplyTableUpdates() may have consumed this update..
if ((*aUpdates)[i]) {
// Run all updates for one table
rv = ApplyTableUpdates(aUpdates, aUpdates->ElementAt(i)->TableName());
nsCString updateTable(aUpdates->ElementAt(i)->TableName());
rv = ApplyTableUpdates(aUpdates, updateTable);
if (NS_FAILED(rv)) {
Reset();
return rv;
@ -372,7 +377,21 @@ Classifier::ApplyUpdates(nsTArray<TableUpdate*>* aUpdates)
}
}
aUpdates->Clear();
RegenActiveTables();
rv = RegenActiveTables();
NS_ENSURE_SUCCESS(rv, rv);
LOG(("Cleaning up backups."));
// Move the backup directory away (signaling the transaction finished
// successfully). This is atomic.
rv = RemoveBackupTables();
NS_ENSURE_SUCCESS(rv, rv);
// Do the actual deletion of the backup files.
rv = CleanToDelete();
NS_ENSURE_SUCCESS(rv, rv);
LOG(("Done applying updates."));
#if defined(PR_LOGGING)
@ -432,6 +451,9 @@ Classifier::RegenActiveTables()
continue;
}
if (!lookupCache->IsPrimed())
continue;
const ChunkSet &adds = store->AddChunks();
const ChunkSet &subs = store->SubChunks();
@ -482,6 +504,102 @@ Classifier::ActiveTables(nsTArray<nsCString>& aTables)
return NS_OK;
}
nsresult
Classifier::CleanToDelete()
{
bool exists;
nsresult rv = mToDeleteDirectory->Exists(&exists);
NS_ENSURE_SUCCESS(rv, rv);
if (exists) {
rv = mToDeleteDirectory->Remove(true);
NS_ENSURE_SUCCESS(rv, rv);
}
return NS_OK;
}
nsresult
Classifier::BackupTables()
{
// We have to work in reverse here: first move the normal directory
// away to be the backup directory, then copy the files over
// to the normal directory. This ensures that if we crash the backup
// dir always has a valid, complete copy, instead of a partial one,
// because that's the one we will copy over the normal store dir.
nsCString backupDirName;
nsresult rv = mBackupDirectory->GetNativeLeafName(backupDirName);
NS_ENSURE_SUCCESS(rv, rv);
nsCString storeDirName;
rv = mStoreDirectory->GetNativeLeafName(storeDirName);
NS_ENSURE_SUCCESS(rv, rv);
rv = mStoreDirectory->MoveToNative(nullptr, backupDirName);
NS_ENSURE_SUCCESS(rv, rv);
rv = mStoreDirectory->CopyToNative(nullptr, storeDirName);
NS_ENSURE_SUCCESS(rv, rv);
// We moved some things to new places, so move the handles around, too.
rv = SetupPathNames();
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
nsresult
Classifier::RemoveBackupTables()
{
nsCString toDeleteName;
nsresult rv = mToDeleteDirectory->GetNativeLeafName(toDeleteName);
NS_ENSURE_SUCCESS(rv, rv);
rv = mBackupDirectory->MoveToNative(nullptr, toDeleteName);
NS_ENSURE_SUCCESS(rv, rv);
// mBackupDirectory now points to toDelete, fix that up.
rv = SetupPathNames();
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
nsresult
Classifier::RecoverBackups()
{
bool backupExists;
nsresult rv = mBackupDirectory->Exists(&backupExists);
NS_ENSURE_SUCCESS(rv, rv);
if (backupExists) {
// Remove the safebrowsing dir if it exists
nsCString storeDirName;
rv = mStoreDirectory->GetNativeLeafName(storeDirName);
NS_ENSURE_SUCCESS(rv, rv);
bool storeExists;
rv = mStoreDirectory->Exists(&storeExists);
NS_ENSURE_SUCCESS(rv, rv);
if (storeExists) {
rv = mStoreDirectory->Remove(true);
NS_ENSURE_SUCCESS(rv, rv);
}
// Move the backup to the store location
rv = mBackupDirectory->MoveToNative(nullptr, storeDirName);
NS_ENSURE_SUCCESS(rv, rv);
// mBackupDirectory now points to storeDir, fix up.
rv = SetupPathNames();
NS_ENSURE_SUCCESS(rv, rv);
}
return NS_OK;
}
/*
* This will consume+delete updates from the passed nsTArray.
*/
@ -592,10 +710,6 @@ Classifier::ApplyTableUpdates(nsTArray<TableUpdate*>* aUpdates,
rv = prefixSet->WriteFile();
NS_ENSURE_SUCCESS(rv, rv);
// This will drop all the temporary storage used during the update.
rv = store->FinishUpdate();
NS_ENSURE_SUCCESS(rv, rv);
if (updateFreshness) {
int64_t now = (PR_Now() / PR_USEC_PER_SEC);
LOG(("Successfully updated %s", store->TableName().get()));

View File

@ -28,8 +28,8 @@ public:
~Classifier();
nsresult Open(nsIFile& aCacheDirectory);
nsresult Close();
nsresult Reset();
void Close();
void Reset();
/**
* Get the list of active tables and their chunks in a format
@ -71,6 +71,11 @@ public:
PrefixArray* aNoiseEntries);
private:
void DropStores();
nsresult SetupPathNames();
nsresult RecoverBackups();
nsresult CleanToDelete();
nsresult BackupTables();
nsresult RemoveBackupTables();
nsresult RegenActiveTables();
nsresult ScanStoreDir(nsTArray<nsCString>& aTables);
@ -80,8 +85,14 @@ private:
LookupCache *GetLookupCache(const nsACString& aTable);
nsresult InitKey();
nsCOMPtr<nsICryptoHash> mCryptoHash;
// Root dir of the Local profile.
nsCOMPtr<nsIFile> mCacheDirectory;
// Main directory where to store the databases.
nsCOMPtr<nsIFile> mStoreDirectory;
// Used for atomically updating the other dirs.
nsCOMPtr<nsIFile> mBackupDirectory;
nsCOMPtr<nsIFile> mToDeleteDirectory;
nsCOMPtr<nsICryptoHash> mCryptoHash;
nsTArray<HashStore*> mHashStores;
nsTArray<LookupCache*> mLookupCaches;
nsTArray<nsCString> mActiveTablesCache;

View File

@ -166,8 +166,6 @@ HashStore::Reset()
rv = storeFile->Remove(false);
NS_ENSURE_SUCCESS(rv, rv);
Clear();
return NS_OK;
}
@ -230,7 +228,6 @@ HashStore::Open()
}
if (rv == NS_ERROR_FILE_NOT_FOUND) {
Clear();
UpdateHeader();
return NS_OK;
}
@ -271,24 +268,9 @@ HashStore::Open()
return NS_OK;
}
void
HashStore::Clear()
{
mAddChunks.Clear();
mSubChunks.Clear();
mAddExpirations.Clear();
mSubExpirations.Clear();
mAddPrefixes.Clear();
mSubPrefixes.Clear();
mAddCompletes.Clear();
mSubCompletes.Clear();
}
nsresult
HashStore::ReadEntireStore()
{
Clear();
nsresult rv = ReadHeader();
NS_ENSURE_SUCCESS(rv, rv);
@ -308,7 +290,6 @@ nsresult
HashStore::ReadHeader()
{
if (!mInputStream) {
Clear();
UpdateHeader();
return NS_OK;
}
@ -409,8 +390,6 @@ nsresult
HashStore::ReadChunkNumbers()
{
if (!mInputStream) {
LOG(("Clearing."));
Clear();
return NS_OK;
}
@ -465,6 +444,11 @@ HashStore::BeginUpdate()
nsresult rv = ReadEntireStore();
NS_ENSURE_SUCCESS(rv, rv);
if (mInputStream) {
rv = mInputStream->Close();
NS_ENSURE_SUCCESS(rv, rv);
}
return NS_OK;
}
@ -835,13 +819,6 @@ HashStore::WriteFile()
rv = storeFile->AppendNative(mTableName + NS_LITERAL_CSTRING(".sbstore"));
NS_ENSURE_SUCCESS(rv, rv);
// Need to close the inputstream here *before* rewriting its file.
// Windows will fail with an access violation if we don't.
if (mInputStream) {
rv = mInputStream->Close();
NS_ENSURE_SUCCESS(rv, rv);
}
nsCOMPtr<nsIOutputStream> out;
rv = NS_NewCheckSummedOutputStream(getter_AddRefs(out), storeFile,
PR_WRONLY | PR_TRUNCATE | PR_CREATE_FILE);
@ -877,32 +854,6 @@ HashStore::WriteFile()
rv = safeOut->Finish();
NS_ENSURE_SUCCESS(rv, rv);
int64_t fileSize;
rv = storeFile->GetFileSize(&fileSize);
NS_ENSURE_SUCCESS(rv, rv);
// Reopen the file now that we've rewritten it.
nsCOMPtr<nsIInputStream> origStream;
rv = NS_NewLocalFileInputStream(getter_AddRefs(origStream), storeFile,
PR_RDONLY);
NS_ENSURE_SUCCESS(rv, rv);
rv = NS_NewBufferedInputStream(getter_AddRefs(mInputStream), origStream,
fileSize);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
nsresult
HashStore::FinishUpdate()
{
// Drop add/sub data, it's only used during updates.
mAddPrefixes.Clear();
mSubPrefixes.Clear();
mAddCompletes.Clear();
mSubCompletes.Clear();
return NS_OK;
}

View File

@ -111,23 +111,17 @@ public:
// have a mess on your hands.
nsresult WriteFile();
// Drop memory used during the update process.
nsresult FinishUpdate();
// Force the entire store in memory
nsresult ReadEntireStore();
private:
void Clear();
nsresult Reset();
nsresult ReadHeader();
// Force the entire store in memory
nsresult ReadEntireStore();
nsresult SanityCheck(nsIFile* aStoreFile);
nsresult CalculateChecksum(nsAutoCString& aChecksum, bool aChecksumPresent);
nsresult CheckChecksum(nsIFile* aStoreFile);
void UpdateHeader();
nsresult EnsureChunkNumbers();
nsresult ReadChunkNumbers();
nsresult ReadHashes();
nsresult ReadAddPrefixes();
@ -158,7 +152,6 @@ private:
nsCOMPtr<nsIInputStream> mInputStream;
bool haveChunks;
ChunkSet mAddChunks;
ChunkSet mSubChunks;

View File

@ -1,41 +1,7 @@
//* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Url Classifier code
*
* The Initial Developer of the Original Code is
* the Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Dave Camp <dcamp@mozilla.com>
* Gian-Carlo Pascutto <gpascutto@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "LookupCache.h"
#include "HashStore.h"
@ -116,7 +82,8 @@ LookupCache::Open()
rv = storeFile->AppendNative(mTableName + NS_LITERAL_CSTRING(CACHE_SUFFIX));
NS_ENSURE_SUCCESS(rv, rv);
rv = NS_NewLocalFileInputStream(getter_AddRefs(mInputStream), storeFile,
nsCOMPtr<nsIInputStream> inputStream;
rv = NS_NewLocalFileInputStream(getter_AddRefs(inputStream), storeFile,
PR_RDONLY);
if (NS_FAILED(rv) && rv != NS_ERROR_FILE_NOT_FOUND) {
@ -125,18 +92,23 @@ LookupCache::Open()
}
if (rv == NS_ERROR_FILE_NOT_FOUND) {
// Simply lacking a .cache file is a recoverable error,
// as unlike the .pset/.sbstore files it is a pure cache.
// Just create a new empty one.
Clear();
UpdateHeader();
return NS_OK;
} else {
// Read in the .cache file
rv = ReadHeader(inputStream);
NS_ENSURE_SUCCESS(rv, rv);
LOG(("ReadCompletions"));
rv = ReadCompletions(inputStream);
NS_ENSURE_SUCCESS(rv, rv);
rv = inputStream->Close();
NS_ENSURE_SUCCESS(rv, rv);
}
rv = ReadHeader();
NS_ENSURE_SUCCESS(rv, rv);
LOG(("ReadCompletions"));
rv = ReadCompletions();
NS_ENSURE_SUCCESS(rv, rv);
LOG(("Loading PrefixSet"));
rv = LoadPrefixSet();
NS_ENSURE_SUCCESS(rv, rv);
@ -144,6 +116,12 @@ LookupCache::Open()
return NS_OK;
}
nsresult
LookupCache::UpdateDirHandle(nsIFile* aStoreDirectory)
{
return aStoreDirectory->Clone(getter_AddRefs(mStoreDirectory));
}
nsresult
LookupCache::Reset()
{
@ -261,13 +239,6 @@ LookupCache::WriteFile()
rv = storeFile->AppendNative(mTableName + NS_LITERAL_CSTRING(CACHE_SUFFIX));
NS_ENSURE_SUCCESS(rv, rv);
// Need to close the inputstream here *before* rewriting its file.
// Windows will fail if we don't.
if (mInputStream) {
rv = mInputStream->Close();
NS_ENSURE_SUCCESS(rv, rv);
}
nsCOMPtr<nsIOutputStream> out;
rv = NS_NewSafeLocalFileOutputStream(getter_AddRefs(out), storeFile,
PR_WRONLY | PR_TRUNCATE | PR_CREATE_FILE);
@ -290,11 +261,6 @@ LookupCache::WriteFile()
rv = EnsureSizeConsistent();
NS_ENSURE_SUCCESS(rv, rv);
// Reopen the file now that we've rewritten it.
rv = NS_NewLocalFileInputStream(getter_AddRefs(mInputStream), storeFile,
PR_RDONLY);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIFile> psFile;
rv = mStoreDirectory->Clone(getter_AddRefs(psFile));
NS_ENSURE_SUCCESS(rv, rv);
@ -353,20 +319,20 @@ LookupCache::EnsureSizeConsistent()
}
nsresult
LookupCache::ReadHeader()
LookupCache::ReadHeader(nsIInputStream* aInputStream)
{
if (!mInputStream) {
if (!aInputStream) {
Clear();
UpdateHeader();
return NS_OK;
}
nsCOMPtr<nsISeekableStream> seekable = do_QueryInterface(mInputStream);
nsCOMPtr<nsISeekableStream> seekable = do_QueryInterface(aInputStream);
nsresult rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, 0);
NS_ENSURE_SUCCESS(rv, rv);
void *buffer = &mHeader;
rv = NS_ReadInputStreamToBuffer(mInputStream,
rv = NS_ReadInputStreamToBuffer(aInputStream,
&buffer,
sizeof(Header));
NS_ENSURE_SUCCESS(rv, rv);
@ -385,18 +351,18 @@ LookupCache::ReadHeader()
}
nsresult
LookupCache::ReadCompletions()
LookupCache::ReadCompletions(nsIInputStream* aInputStream)
{
if (!mHeader.numCompletions) {
mCompletions.Clear();
return NS_OK;
}
nsCOMPtr<nsISeekableStream> seekable = do_QueryInterface(mInputStream);
nsCOMPtr<nsISeekableStream> seekable = do_QueryInterface(aInputStream);
nsresult rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, sizeof(Header));
NS_ENSURE_SUCCESS(rv, rv);
rv = ReadTArray(mInputStream, &mCompletions, mHeader.numCompletions);
rv = ReadTArray(aInputStream, &mCompletions, mHeader.numCompletions);
NS_ENSURE_SUCCESS(rv, rv);
LOG(("Read %d completions", mCompletions.Length()));
@ -763,11 +729,15 @@ LookupCache::LoadPrefixSet()
if (exists) {
LOG(("stored PrefixSet exists, loading from disk"));
rv = mPrefixSet->LoadFromFile(psFile);
}
if (!exists || NS_FAILED(rv)) {
LOG(("no (usable) stored PrefixSet found"));
} else {
if (NS_FAILED(rv)) {
if (rv == NS_ERROR_FILE_CORRUPTED) {
Reset();
}
return rv;
}
mPrimed = true;
} else {
LOG(("no (usable) stored PrefixSet found"));
}
#ifdef DEBUG

View File

@ -12,6 +12,7 @@
#include "nsAutoPtr.h"
#include "nsCOMPtr.h"
#include "nsIFile.h"
#include "nsIFileStreams.h"
#include "nsUrlClassifierPrefixSet.h"
#include "prlog.h"
@ -106,6 +107,9 @@ public:
nsresult Init();
nsresult Open();
// The directory handle where we operate will
// be moved away when a backup is made.
nsresult UpdateDirHandle(nsIFile* aStoreDirectory);
// This will Clear() the passed arrays when done.
nsresult Build(AddPrefixArray& aAddPrefixes,
AddCompleteArray& aAddCompletes);
@ -123,13 +127,12 @@ public:
bool IsPrimed();
private:
void Clear();
nsresult Reset();
void UpdateHeader();
nsresult ReadHeader();
nsresult ReadHeader(nsIInputStream* aInputStream);
nsresult ReadCompletions(nsIInputStream* aInputStream);
nsresult EnsureSizeConsistent();
nsresult ReadCompletions();
nsresult LoadPrefixSet();
// Construct a Prefix Set with known prefixes.
// This will Clear() aAddPrefixes when done.
@ -146,7 +149,6 @@ private:
bool mPerClientRandomize;
nsCString mTableName;
nsCOMPtr<nsIFile> mStoreDirectory;
nsCOMPtr<nsIInputStream> mInputStream;
CompletionArray mCompletions;
// Set of prefixes known to be in the database
nsRefPtr<nsUrlClassifierPrefixSet> mPrefixSet;

View File

@ -352,7 +352,7 @@ nsUrlClassifierPrefixSet::LoadFromFd(AutoFDClose& fileFd)
if (indexSize == 0) {
LOG(("stored PrefixSet is empty!"));
return NS_ERROR_FAILURE;
return NS_OK;
}
if (deltaSize > (indexSize * DELTAS_LIMIT)) {
@ -377,7 +377,7 @@ nsUrlClassifierPrefixSet::LoadFromFd(AutoFDClose& fileFd)
mHasPrefixes = true;
} else {
LOG(("Version magic mismatch, not loading"));
return NS_ERROR_FAILURE;
return NS_ERROR_FILE_CORRUPTED;
}
LOG(("Loading PrefixSet successful"));