toolkit/components/url-classifier/LookupCache.cpp

Fri, 16 Jan 2015 18:13:44 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 16 Jan 2015 18:13:44 +0100
branch
TOR_BUG_9701
changeset 14
925c144e1f1f
permissions
-rw-r--r--

Integrate suggestion from review to improve consistency with existing code.

     1 //* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #include "LookupCache.h"
     7 #include "HashStore.h"
     8 #include "nsISeekableStream.h"
     9 #include "mozilla/Telemetry.h"
    10 #include "prlog.h"
    11 #include "prprf.h"
    13 // We act as the main entry point for all the real lookups,
    14 // so note that those are not done to the actual HashStore.
    15 // The latter solely exists to store the data needed to handle
    16 // the updates from the protocol.
    18 // This module has its own store, which stores the Completions,
    19 // mostly caching lookups that have happened over the net.
    20 // The prefixes are cached/checked by looking them up in the
    21 // PrefixSet.
    23 // Data format for the ".cache" files:
    24 //    uint32_t magic           Identify the file type
    25 //    uint32_t version         Version identifier for file format
    26 //    uint32_t numCompletions  Amount of completions stored
    27 //    0...numCompletions     256-bit Completions
    29 // Name of the lookupcomplete cache
    30 #define CACHE_SUFFIX ".cache"
    32 // Name of the persistent PrefixSet storage
    33 #define PREFIXSET_SUFFIX  ".pset"
    35 // NSPR_LOG_MODULES=UrlClassifierDbService:5
    36 extern PRLogModuleInfo *gUrlClassifierDbServiceLog;
    37 #if defined(PR_LOGGING)
    38 #define LOG(args) PR_LOG(gUrlClassifierDbServiceLog, PR_LOG_DEBUG, args)
    39 #define LOG_ENABLED() PR_LOG_TEST(gUrlClassifierDbServiceLog, 4)
    40 #else
    41 #define LOG(args)
    42 #define LOG_ENABLED() (false)
    43 #endif
    45 namespace mozilla {
    46 namespace safebrowsing {
    48 const uint32_t LOOKUPCACHE_MAGIC = 0x1231af3e;
    49 const uint32_t CURRENT_VERSION = 2;
    51 LookupCache::LookupCache(const nsACString& aTableName, nsIFile* aStoreDir)
    52   : mPrimed(false)
    53   , mTableName(aTableName)
    54   , mStoreDirectory(aStoreDir)
    55 {
    56 }
    58 nsresult
    59 LookupCache::Init()
    60 {
    61   mPrefixSet = new nsUrlClassifierPrefixSet();
    62   nsresult rv = mPrefixSet->Init(mTableName);
    63   NS_ENSURE_SUCCESS(rv, rv);
    65   return NS_OK;
    66 }
    68 LookupCache::~LookupCache()
    69 {
    70 }
    72 nsresult
    73 LookupCache::Open()
    74 {
    75   nsCOMPtr<nsIFile> storeFile;
    77   nsresult rv = mStoreDirectory->Clone(getter_AddRefs(storeFile));
    78   NS_ENSURE_SUCCESS(rv, rv);
    80   rv = storeFile->AppendNative(mTableName + NS_LITERAL_CSTRING(CACHE_SUFFIX));
    81   NS_ENSURE_SUCCESS(rv, rv);
    83   nsCOMPtr<nsIInputStream> inputStream;
    84   rv = NS_NewLocalFileInputStream(getter_AddRefs(inputStream), storeFile,
    85                                   PR_RDONLY | nsIFile::OS_READAHEAD);
    87   if (NS_FAILED(rv) && rv != NS_ERROR_FILE_NOT_FOUND) {
    88     Reset();
    89     return rv;
    90   }
    92   if (rv == NS_ERROR_FILE_NOT_FOUND) {
    93     // Simply lacking a .cache file is a recoverable error,
    94     // as unlike the .pset/.sbstore files it is a pure cache.
    95     // Just create a new empty one.
    96     ClearCompleteCache();
    97   } else {
    98     // Read in the .cache file
    99     rv = ReadHeader(inputStream);
   100     NS_ENSURE_SUCCESS(rv, rv);
   101     LOG(("ReadCompletions"));
   102     rv = ReadCompletions(inputStream);
   103     NS_ENSURE_SUCCESS(rv, rv);
   105     rv = inputStream->Close();
   106     NS_ENSURE_SUCCESS(rv, rv);
   107   }
   109   LOG(("Loading PrefixSet"));
   110   rv = LoadPrefixSet();
   111   NS_ENSURE_SUCCESS(rv, rv);
   113   return NS_OK;
   114 }
   116 nsresult
   117 LookupCache::UpdateDirHandle(nsIFile* aStoreDirectory)
   118 {
   119   return aStoreDirectory->Clone(getter_AddRefs(mStoreDirectory));
   120 }
   122 nsresult
   123 LookupCache::Reset()
   124 {
   125   LOG(("LookupCache resetting"));
   127   nsCOMPtr<nsIFile> storeFile;
   128   nsCOMPtr<nsIFile> prefixsetFile;
   129   nsresult rv = mStoreDirectory->Clone(getter_AddRefs(storeFile));
   130   NS_ENSURE_SUCCESS(rv, rv);
   131   rv = mStoreDirectory->Clone(getter_AddRefs(prefixsetFile));
   132   NS_ENSURE_SUCCESS(rv, rv);
   134   rv = storeFile->AppendNative(mTableName + NS_LITERAL_CSTRING(CACHE_SUFFIX));
   135   NS_ENSURE_SUCCESS(rv, rv);
   136   rv = prefixsetFile->AppendNative(mTableName + NS_LITERAL_CSTRING(PREFIXSET_SUFFIX));
   137   NS_ENSURE_SUCCESS(rv, rv);
   139   rv = storeFile->Remove(false);
   140   NS_ENSURE_SUCCESS(rv, rv);
   141   rv = prefixsetFile->Remove(false);
   142   NS_ENSURE_SUCCESS(rv, rv);
   144   ClearAll();
   146   return NS_OK;
   147 }
   150 nsresult
   151 LookupCache::Build(AddPrefixArray& aAddPrefixes,
   152                    AddCompleteArray& aAddCompletes)
   153 {
   154   Telemetry::Accumulate(Telemetry::URLCLASSIFIER_LC_COMPLETIONS,
   155                         static_cast<uint32_t>(aAddCompletes.Length()));
   157   mCompletions.Clear();
   158   mCompletions.SetCapacity(aAddCompletes.Length());
   159   for (uint32_t i = 0; i < aAddCompletes.Length(); i++) {
   160     mCompletions.AppendElement(aAddCompletes[i].CompleteHash());
   161   }
   162   aAddCompletes.Clear();
   163   mCompletions.Sort();
   165   Telemetry::Accumulate(Telemetry::URLCLASSIFIER_LC_PREFIXES,
   166                         static_cast<uint32_t>(aAddPrefixes.Length()));
   168   nsresult rv = ConstructPrefixSet(aAddPrefixes);
   169   NS_ENSURE_SUCCESS(rv, rv);
   170   mPrimed = true;
   172   return NS_OK;
   173 }
   175 #if defined(DEBUG) && defined(PR_LOGGING)
   176 void
   177 LookupCache::Dump()
   178 {
   179   if (!LOG_ENABLED())
   180     return;
   182   for (uint32_t i = 0; i < mCompletions.Length(); i++) {
   183     nsAutoCString str;
   184     mCompletions[i].ToString(str);
   185     LOG(("Completion: %s", str.get()));
   186   }
   187 }
   188 #endif
   190 nsresult
   191 LookupCache::Has(const Completion& aCompletion,
   192                  bool* aHas, bool* aComplete)
   193 {
   194   *aHas = *aComplete = false;
   196   uint32_t prefix = aCompletion.ToUint32();
   198   bool found;
   199   nsresult rv = mPrefixSet->Contains(prefix, &found);
   200   NS_ENSURE_SUCCESS(rv, rv);
   202   LOG(("Probe in %s: %X, found %d", mTableName.get(), prefix, found));
   204   if (found) {
   205     *aHas = true;
   206   }
   208   if (mCompletions.BinaryIndexOf(aCompletion) != nsTArray<Completion>::NoIndex) {
   209     LOG(("Complete in %s", mTableName.get()));
   210     *aComplete = true;
   211     *aHas = true;
   212   }
   214   return NS_OK;
   215 }
   217 nsresult
   218 LookupCache::WriteFile()
   219 {
   220   nsCOMPtr<nsIFile> storeFile;
   221   nsresult rv = mStoreDirectory->Clone(getter_AddRefs(storeFile));
   222   NS_ENSURE_SUCCESS(rv, rv);
   223   rv = storeFile->AppendNative(mTableName + NS_LITERAL_CSTRING(CACHE_SUFFIX));
   224   NS_ENSURE_SUCCESS(rv, rv);
   226   nsCOMPtr<nsIOutputStream> out;
   227   rv = NS_NewSafeLocalFileOutputStream(getter_AddRefs(out), storeFile,
   228                                        PR_WRONLY | PR_TRUNCATE | PR_CREATE_FILE);
   229   NS_ENSURE_SUCCESS(rv, rv);
   231   UpdateHeader();
   232   LOG(("Writing %d completions", mHeader.numCompletions));
   234   uint32_t written;
   235   rv = out->Write(reinterpret_cast<char*>(&mHeader), sizeof(mHeader), &written);
   236   NS_ENSURE_SUCCESS(rv, rv);
   238   rv = WriteTArray(out, mCompletions);
   239   NS_ENSURE_SUCCESS(rv, rv);
   241   nsCOMPtr<nsISafeOutputStream> safeOut = do_QueryInterface(out);
   242   rv = safeOut->Finish();
   243   NS_ENSURE_SUCCESS(rv, rv);
   245   rv = EnsureSizeConsistent();
   246   NS_ENSURE_SUCCESS(rv, rv);
   248   nsCOMPtr<nsIFile> psFile;
   249   rv = mStoreDirectory->Clone(getter_AddRefs(psFile));
   250   NS_ENSURE_SUCCESS(rv, rv);
   252   rv = psFile->AppendNative(mTableName + NS_LITERAL_CSTRING(PREFIXSET_SUFFIX));
   253   NS_ENSURE_SUCCESS(rv, rv);
   255   rv = mPrefixSet->StoreToFile(psFile);
   256   NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "failed to store the prefixset");
   258   return NS_OK;
   259 }
   261 void
   262 LookupCache::ClearAll()
   263 {
   264   ClearCompleteCache();
   265   mPrefixSet->SetPrefixes(nullptr, 0);
   266   mPrimed = false;
   267 }
   269 void
   270 LookupCache::ClearCompleteCache()
   271 {
   272   mCompletions.Clear();
   273   UpdateHeader();
   274 }
   276 void
   277 LookupCache::UpdateHeader()
   278 {
   279   mHeader.magic = LOOKUPCACHE_MAGIC;
   280   mHeader.version = CURRENT_VERSION;
   281   mHeader.numCompletions = mCompletions.Length();
   282 }
   284 nsresult
   285 LookupCache::EnsureSizeConsistent()
   286 {
   287   nsCOMPtr<nsIFile> storeFile;
   288   nsresult rv = mStoreDirectory->Clone(getter_AddRefs(storeFile));
   289   NS_ENSURE_SUCCESS(rv, rv);
   290   rv = storeFile->AppendNative(mTableName + NS_LITERAL_CSTRING(CACHE_SUFFIX));
   291   NS_ENSURE_SUCCESS(rv, rv);
   293   int64_t fileSize;
   294   rv = storeFile->GetFileSize(&fileSize);
   295   NS_ENSURE_SUCCESS(rv, rv);
   297   if (fileSize < 0) {
   298     return NS_ERROR_FAILURE;
   299   }
   301   int64_t expectedSize = sizeof(mHeader)
   302                         + mHeader.numCompletions*sizeof(Completion);
   303   if (expectedSize != fileSize) {
   304     NS_WARNING("File length does not match. Probably corrupted.");
   305     Reset();
   306     return NS_ERROR_FILE_CORRUPTED;
   307   }
   309   return NS_OK;
   310 }
   312 nsresult
   313 LookupCache::ReadHeader(nsIInputStream* aInputStream)
   314 {
   315   if (!aInputStream) {
   316     ClearCompleteCache();
   317     return NS_OK;
   318   }
   320   nsCOMPtr<nsISeekableStream> seekable = do_QueryInterface(aInputStream);
   321   nsresult rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, 0);
   322   NS_ENSURE_SUCCESS(rv, rv);
   324   void *buffer = &mHeader;
   325   rv = NS_ReadInputStreamToBuffer(aInputStream,
   326                                   &buffer,
   327                                   sizeof(Header));
   328   NS_ENSURE_SUCCESS(rv, rv);
   330   if (mHeader.magic != LOOKUPCACHE_MAGIC || mHeader.version != CURRENT_VERSION) {
   331     NS_WARNING("Unexpected header data in the store.");
   332     Reset();
   333     return NS_ERROR_FILE_CORRUPTED;
   334   }
   335   LOG(("%d completions present", mHeader.numCompletions));
   337   rv = EnsureSizeConsistent();
   338   NS_ENSURE_SUCCESS(rv, rv);
   340   return NS_OK;
   341 }
   343 nsresult
   344 LookupCache::ReadCompletions(nsIInputStream* aInputStream)
   345 {
   346   if (!mHeader.numCompletions) {
   347     mCompletions.Clear();
   348     return NS_OK;
   349   }
   351   nsCOMPtr<nsISeekableStream> seekable = do_QueryInterface(aInputStream);
   352   nsresult rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, sizeof(Header));
   353   NS_ENSURE_SUCCESS(rv, rv);
   355   rv = ReadTArray(aInputStream, &mCompletions, mHeader.numCompletions);
   356   NS_ENSURE_SUCCESS(rv, rv);
   358   LOG(("Read %d completions", mCompletions.Length()));
   360   return NS_OK;
   361 }
   363 /* static */ bool
   364 LookupCache::IsCanonicalizedIP(const nsACString& aHost)
   365 {
   366   // The canonicalization process will have left IP addresses in dotted
   367   // decimal with no surprises.
   368   uint32_t i1, i2, i3, i4;
   369   char c;
   370   if (PR_sscanf(PromiseFlatCString(aHost).get(), "%u.%u.%u.%u%c",
   371                 &i1, &i2, &i3, &i4, &c) == 4) {
   372     return (i1 <= 0xFF && i2 <= 0xFF && i3 <= 0xFF && i4 <= 0xFF);
   373   }
   375   return false;
   376 }
   378 /* static */ nsresult
   379 LookupCache::GetKey(const nsACString& aSpec,
   380                     Completion* aHash,
   381                     nsCOMPtr<nsICryptoHash>& aCryptoHash)
   382 {
   383   nsACString::const_iterator begin, end, iter;
   384   aSpec.BeginReading(begin);
   385   aSpec.EndReading(end);
   387   iter = begin;
   388   if (!FindCharInReadable('/', iter, end)) {
   389    return NS_OK;
   390   }
   392   const nsCSubstring& host = Substring(begin, iter);
   394   if (IsCanonicalizedIP(host)) {
   395     nsAutoCString key;
   396     key.Assign(host);
   397     key.Append("/");
   398     return aHash->FromPlaintext(key, aCryptoHash);
   399   }
   401   nsTArray<nsCString> hostComponents;
   402   ParseString(PromiseFlatCString(host), '.', hostComponents);
   404   if (hostComponents.Length() < 2)
   405     return NS_ERROR_FAILURE;
   407   int32_t last = int32_t(hostComponents.Length()) - 1;
   408   nsAutoCString lookupHost;
   410   if (hostComponents.Length() > 2) {
   411     lookupHost.Append(hostComponents[last - 2]);
   412     lookupHost.Append(".");
   413   }
   415   lookupHost.Append(hostComponents[last - 1]);
   416   lookupHost.Append(".");
   417   lookupHost.Append(hostComponents[last]);
   418   lookupHost.Append("/");
   420   return aHash->FromPlaintext(lookupHost, aCryptoHash);
   421 }
   423 /* static */ nsresult
   424 LookupCache::GetLookupFragments(const nsACString& aSpec,
   425                                 nsTArray<nsCString>* aFragments)
   427 {
   428   aFragments->Clear();
   430   nsACString::const_iterator begin, end, iter;
   431   aSpec.BeginReading(begin);
   432   aSpec.EndReading(end);
   434   iter = begin;
   435   if (!FindCharInReadable('/', iter, end)) {
   436     return NS_OK;
   437   }
   439   const nsCSubstring& host = Substring(begin, iter++);
   440   nsAutoCString path;
   441   path.Assign(Substring(iter, end));
   443   /**
   444    * From the protocol doc:
   445    * For the hostname, the client will try at most 5 different strings.  They
   446    * are:
   447    * a) The exact hostname of the url
   448    * b) The 4 hostnames formed by starting with the last 5 components and
   449    *    successivly removing the leading component.  The top-level component
   450    *    can be skipped. This is not done if the hostname is a numerical IP.
   451    */
   452   nsTArray<nsCString> hosts;
   453   hosts.AppendElement(host);
   455   if (!IsCanonicalizedIP(host)) {
   456     host.BeginReading(begin);
   457     host.EndReading(end);
   458     int numHostComponents = 0;
   459     while (RFindInReadable(NS_LITERAL_CSTRING("."), begin, end) &&
   460            numHostComponents < MAX_HOST_COMPONENTS) {
   461       // don't bother checking toplevel domains
   462       if (++numHostComponents >= 2) {
   463         host.EndReading(iter);
   464         hosts.AppendElement(Substring(end, iter));
   465       }
   466       end = begin;
   467       host.BeginReading(begin);
   468     }
   469   }
   471   /**
   472    * From the protocol doc:
   473    * For the path, the client will also try at most 6 different strings.
   474    * They are:
   475    * a) the exact path of the url, including query parameters
   476    * b) the exact path of the url, without query parameters
   477    * c) the 4 paths formed by starting at the root (/) and
   478    *    successively appending path components, including a trailing
   479    *    slash.  This behavior should only extend up to the next-to-last
   480    *    path component, that is, a trailing slash should never be
   481    *    appended that was not present in the original url.
   482    */
   483   nsTArray<nsCString> paths;
   484   nsAutoCString pathToAdd;
   486   path.BeginReading(begin);
   487   path.EndReading(end);
   488   iter = begin;
   489   if (FindCharInReadable('?', iter, end)) {
   490     pathToAdd = Substring(begin, iter);
   491     paths.AppendElement(pathToAdd);
   492     end = iter;
   493   }
   495   int numPathComponents = 1;
   496   iter = begin;
   497   while (FindCharInReadable('/', iter, end) &&
   498          numPathComponents < MAX_PATH_COMPONENTS) {
   499     iter++;
   500     pathToAdd.Assign(Substring(begin, iter));
   501     paths.AppendElement(pathToAdd);
   502     numPathComponents++;
   503   }
   505   // If we haven't already done so, add the full path
   506   if (!pathToAdd.Equals(path)) {
   507     paths.AppendElement(path);
   508   }
   509   // Check an empty path (for whole-domain blacklist entries)
   510   paths.AppendElement(EmptyCString());
   512   for (uint32_t hostIndex = 0; hostIndex < hosts.Length(); hostIndex++) {
   513     for (uint32_t pathIndex = 0; pathIndex < paths.Length(); pathIndex++) {
   514       nsCString key;
   515       key.Assign(hosts[hostIndex]);
   516       key.Append('/');
   517       key.Append(paths[pathIndex]);
   518       LOG(("Checking fragment %s", key.get()));
   520       aFragments->AppendElement(key);
   521     }
   522   }
   524   return NS_OK;
   525 }
   527 /* static */ nsresult
   528 LookupCache::GetHostKeys(const nsACString& aSpec,
   529                          nsTArray<nsCString>* aHostKeys)
   530 {
   531   nsACString::const_iterator begin, end, iter;
   532   aSpec.BeginReading(begin);
   533   aSpec.EndReading(end);
   535   iter = begin;
   536   if (!FindCharInReadable('/', iter, end)) {
   537     return NS_OK;
   538   }
   540   const nsCSubstring& host = Substring(begin, iter);
   542   if (IsCanonicalizedIP(host)) {
   543     nsCString *key = aHostKeys->AppendElement();
   544     if (!key)
   545       return NS_ERROR_OUT_OF_MEMORY;
   547     key->Assign(host);
   548     key->Append("/");
   549     return NS_OK;
   550   }
   552   nsTArray<nsCString> hostComponents;
   553   ParseString(PromiseFlatCString(host), '.', hostComponents);
   555   if (hostComponents.Length() < 2) {
   556     // no host or toplevel host, this won't match anything in the db
   557     return NS_OK;
   558   }
   560   // First check with two domain components
   561   int32_t last = int32_t(hostComponents.Length()) - 1;
   562   nsCString *lookupHost = aHostKeys->AppendElement();
   563   if (!lookupHost)
   564     return NS_ERROR_OUT_OF_MEMORY;
   566   lookupHost->Assign(hostComponents[last - 1]);
   567   lookupHost->Append(".");
   568   lookupHost->Append(hostComponents[last]);
   569   lookupHost->Append("/");
   571   // Now check with three domain components
   572   if (hostComponents.Length() > 2) {
   573     nsCString *lookupHost2 = aHostKeys->AppendElement();
   574     if (!lookupHost2)
   575       return NS_ERROR_OUT_OF_MEMORY;
   576     lookupHost2->Assign(hostComponents[last - 2]);
   577     lookupHost2->Append(".");
   578     lookupHost2->Append(*lookupHost);
   579   }
   581   return NS_OK;
   582 }
   584 bool LookupCache::IsPrimed()
   585 {
   586   return mPrimed;
   587 }
   589 #ifdef DEBUG
   590 template <class T>
   591 static void EnsureSorted(T* aArray)
   592 {
   593   typename T::elem_type* start = aArray->Elements();
   594   typename T::elem_type* end = aArray->Elements() + aArray->Length();
   595   typename T::elem_type* iter = start;
   596   typename T::elem_type* previous = start;
   598   while (iter != end) {
   599     previous = iter;
   600     ++iter;
   601     if (iter != end) {
   602       MOZ_ASSERT(*previous <= *iter);
   603     }
   604   }
   605   return;
   606 }
   607 #endif
   609 nsresult
   610 LookupCache::ConstructPrefixSet(AddPrefixArray& aAddPrefixes)
   611 {
   612   Telemetry::AutoTimer<Telemetry::URLCLASSIFIER_PS_CONSTRUCT_TIME> timer;
   614   nsTArray<uint32_t> array;
   615   array.SetCapacity(aAddPrefixes.Length());
   617   for (uint32_t i = 0; i < aAddPrefixes.Length(); i++) {
   618     array.AppendElement(aAddPrefixes[i].PrefixHash().ToUint32());
   619   }
   620   aAddPrefixes.Clear();
   622 #ifdef DEBUG
   623   // PrefixSet requires sorted order
   624   EnsureSorted(&array);
   625 #endif
   627   // construct new one, replace old entries
   628   nsresult rv = mPrefixSet->SetPrefixes(array.Elements(), array.Length());
   629   if (NS_FAILED(rv)) {
   630     goto error_bailout;
   631   }
   633 #ifdef DEBUG
   634   uint32_t size;
   635   size = mPrefixSet->SizeOfIncludingThis(moz_malloc_size_of);
   636   LOG(("SB tree done, size = %d bytes\n", size));
   637 #endif
   639   mPrimed = true;
   641   return NS_OK;
   643  error_bailout:
   644   Telemetry::Accumulate(Telemetry::URLCLASSIFIER_PS_FAILURE, 1);
   645   return rv;
   646 }
   648 nsresult
   649 LookupCache::LoadPrefixSet()
   650 {
   651   nsCOMPtr<nsIFile> psFile;
   652   nsresult rv = mStoreDirectory->Clone(getter_AddRefs(psFile));
   653   NS_ENSURE_SUCCESS(rv, rv);
   655   rv = psFile->AppendNative(mTableName + NS_LITERAL_CSTRING(PREFIXSET_SUFFIX));
   656   NS_ENSURE_SUCCESS(rv, rv);
   658   bool exists;
   659   rv = psFile->Exists(&exists);
   660   NS_ENSURE_SUCCESS(rv, rv);
   662   if (exists) {
   663     LOG(("stored PrefixSet exists, loading from disk"));
   664     rv = mPrefixSet->LoadFromFile(psFile);
   665     if (NS_FAILED(rv)) {
   666       if (rv == NS_ERROR_FILE_CORRUPTED) {
   667         Reset();
   668       }
   669       return rv;
   670     }
   671     mPrimed = true;
   672   } else {
   673     LOG(("no (usable) stored PrefixSet found"));
   674   }
   676 #ifdef DEBUG
   677   if (mPrimed) {
   678     uint32_t size = mPrefixSet->SizeOfIncludingThis(moz_malloc_size_of);
   679     LOG(("SB tree done, size = %d bytes\n", size));
   680   }
   681 #endif
   683   return NS_OK;
   684 }
   686 nsresult
   687 LookupCache::GetPrefixes(nsTArray<uint32_t>* aAddPrefixes)
   688 {
   689   if (!mPrimed) {
   690     // This can happen if its a new table, so no error.
   691     LOG(("GetPrefixes from empty LookupCache"));
   692     return NS_OK;
   693   }
   694   uint32_t cnt;
   695   uint32_t *arr;
   696   nsresult rv = mPrefixSet->GetPrefixes(&cnt, &arr);
   697   NS_ENSURE_SUCCESS(rv, rv);
   698   if (!aAddPrefixes->AppendElements(arr, cnt))
   699     return NS_ERROR_FAILURE;
   700   nsMemory::Free(arr);
   701   return NS_OK;
   702 }
   705 }
   706 }

mercurial