LCOV - app.info - toolkit/components/url-classifier/HashStore.cpp

LCOV - code coverage report
| Current view: | directory - toolkit/components/url-classifier - HashStore.cpp (source / functions) |  | Found | Hit | Coverage |
| Test: | app.info | Lines: | 517 | 469 | 90.7 %
| Date: | 2012-04-21 | Functions: | 49 | 48 | 98.0 %

           1                 : //* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
           2                 : // Originally based on Chrome sources:
           3                 : // Copyright (c) 2010 The Chromium Authors. All rights reserved.
           4                 : //
           5                 : // Redistribution and use in source and binary forms, with or without
           6                 : // modification, are permitted provided that the following conditions are
           7                 : // met:
           8                 : //
           9                 : //    * Redistributions of source code must retain the above copyright
          10                 : // notice, this list of conditions and the following disclaimer.
          11                 : //    * Redistributions in binary form must reproduce the above
          12                 : // copyright notice, this list of conditions and the following disclaimer
          13                 : // in the documentation and/or other materials provided with the
          14                 : // distribution.
          15                 : //    * Neither the name of Google Inc. nor the names of its
          16                 : // contributors may be used to endorse or promote products derived from
          17                 : // this software without specific prior written permission.
          18                 : //
          19                 : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
          20                 : // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
          21                 : // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
          22                 : // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
          23                 : // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
          24                 : // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
          25                 : // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
          26                 : // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
          27                 : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
          28                 : // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
          29                 : // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
          30                 :
          31                 :
          32                 : #include "HashStore.h"
          33                 : #include "nsAutoPtr.h"
          34                 : #include "nsICryptoHash.h"
          35                 : #include "nsISeekableStream.h"
          36                 : #include "nsIStreamConverterService.h"
          37                 : #include "nsNetUtil.h"
          38                 : #include "nsCheckSummedOutputStream.h"
          39                 : #include "prlog.h"
          40                 : #include "zlib.h"
          41                 :
          42                 : // Main store for SafeBrowsing protocol data. We store
          43                 : // known add/sub chunks, prefixes and completions in memory
          44                 : // during an update, and serialize to disk.
          45                 : // We do not store the add prefixes, those are retrieved by
          46                 : // decompressing the PrefixSet cache whenever we need to apply
          47                 : // an update.
          48                 : //
          49                 : // byte slicing: Many of the 4-byte values stored here are strongly
          50                 : // correlated in the upper bytes, and uncorrelated in the lower
          51                 : // bytes. Because zlib/DEFLATE requires match lengths of at least
          52                 : // 3 to achieve good compression, and we don't get those if only
          53                 : // the upper 16-bits are correlated, it is worthwhile to slice 32-bit
          54                 : // values into 4 1-byte slices and compress the slices individually.
          55                 : // The slices corresponding to MSBs will compress very well, and the
          56                 : // slice corresponding to LSB almost nothing. Because of this, we
          57                 : // only apply DEFLATE to the 3 most significant bytes, and store the
          58                 : // LSB uncompressed.
          59                 : //
          60                 : // byte sliced (numValues) data format:
          61                 : //    uint32 compressed-size
          62                 : //    compressed-size bytes    zlib DEFLATE data
          63                 : //        0...numValues        byte MSB of 4-byte numValues data
          64                 : //    uint32 compressed-size
          65                 : //    compressed-size bytes    zlib DEFLATE data
          66                 : //        0...numValues        byte 2nd byte of 4-byte numValues data
          67                 : //    uint32 compressed-size
          68                 : //    compressed-size bytes    zlib DEFLATE data
          69                 : //        0...numValues        byte 3rd byte of 4-byte numValues data
          70                 : //    0...numValues            byte LSB of 4-byte numValues data
          71                 : //
          72                 : // Store data format:
          73                 : //    uint32 magic
          74                 : //    uint32 version
          75                 : //    uint32 numAddChunks
          76                 : //    uint32 numSubChunks
          77                 : //    uint32 numAddPrefixes
          78                 : //    uint32 numSubPrefixes
          79                 : //    uint32 numAddCompletes
          80                 : //    uint32 numSubCompletes
          81                 : //    0...numAddChunks               uint32 addChunk
          82                 : //    0...numSubChunks               uint32 subChunk
          83                 : //    byte sliced (numAddPrefixes)   uint32 add chunk of AddPrefixes
          84                 : //    byte sliced (numSubPrefixes)   uint32 sub chunk of SubPrefixes
          85                 : //    byte sliced (numSubPrefixes)   uint32 add chunk of SubPrefixes
          86                 : //    byte sliced (numSubPrefixes)   uint32 SubPrefixes
          87                 : //    0...numAddCompletes           32-byte Completions
          88                 : //    0...numSubCompletes           32-byte Completions
          89                 : //    16-byte MD5 of all preceding data
          90                 :
          91                 : // NSPR_LOG_MODULES=UrlClassifierDbService:5
          92                 : extern PRLogModuleInfo *gUrlClassifierDbServiceLog;
          93                 : #if defined(PR_LOGGING)
          94                 : #define LOG(args) PR_LOG(gUrlClassifierDbServiceLog, PR_LOG_DEBUG, args)
          95                 : #define LOG_ENABLED() PR_LOG_TEST(gUrlClassifierDbServiceLog, 4)
          96                 : #else
          97                 : #define LOG(args)
          98                 : #define LOG_ENABLED() (PR_FALSE)
          99                 : #endif
         100                 :
         101                 : namespace mozilla {
         102                 : namespace safebrowsing {
         103                 :
         104                 : const uint32 STORE_MAGIC = 0x1231af3b;
         105                 : const uint32 CURRENT_VERSION = 2;
         106                 :
         107                 : void
         108              45 : TableUpdate::NewAddPrefix(PRUint32 aAddChunk, const Prefix& aHash)
         109                 : {
         110              45 :   AddPrefix *add = mAddPrefixes.AppendElement();
         111              45 :   add->addChunk = aAddChunk;
         112              45 :   add->prefix = aHash;
         113              45 : }
         114                 :
         115                 : void
         116               2 : TableUpdate::NewSubPrefix(PRUint32 aAddChunk, const Prefix& aHash, PRUint32 aSubChunk)
         117                 : {
         118               2 :   SubPrefix *sub = mSubPrefixes.AppendElement();
         119               2 :   sub->addChunk = aAddChunk;
         120               2 :   sub->prefix = aHash;
         121               2 :   sub->subChunk = aSubChunk;
         122               2 : }
         123                 :
         124                 : void
         125             141 : TableUpdate::NewAddComplete(PRUint32 aAddChunk, const Completion& aHash)
         126                 : {
         127             141 :   AddComplete *add = mAddCompletes.AppendElement();
         128             141 :   add->addChunk = aAddChunk;
         129             141 :   add->hash.complete = aHash;
         130             141 : }
         131                 :
         132                 : void
         133              24 : TableUpdate::NewSubComplete(PRUint32 aAddChunk, const Completion& aHash, PRUint32 aSubChunk)
         134                 : {
         135              24 :   SubComplete *sub = mSubCompletes.AppendElement();
         136              24 :   sub->addChunk = aAddChunk;
         137              24 :   sub->hash.complete = aHash;
         138              24 :   sub->subChunk = aSubChunk;
         139              24 : }
         140                 :
         141                 :
         142             244 : HashStore::HashStore(const nsACString& aTableName, nsIFile* aStoreDir)
         143                 :   : mTableName(aTableName)
         144                 :   , mStoreDirectory(aStoreDir)
         145             244 :   , mInUpdate(false)
         146                 : {
         147             244 : }
         148                 :
         149             244 : HashStore::~HashStore()
         150                 : {
         151             244 : }
         152                 :
         153                 : nsresult
         154               0 : HashStore::Reset()
         155                 : {
         156               0 :   LOG(("HashStore resetting"));
         157                 :
         158               0 :   nsCOMPtr<nsIFile> storeFile;
         159               0 :   nsresult rv = mStoreDirectory->Clone(getter_AddRefs(storeFile));
         160               0 :   NS_ENSURE_SUCCESS(rv, rv);
         161                 :
         162               0 :   rv = storeFile->AppendNative(mTableName + NS_LITERAL_CSTRING(".sbstore"));
         163               0 :   NS_ENSURE_SUCCESS(rv, rv);
         164                 :
         165               0 :   rv = storeFile->Remove(PR_FALSE);
         166               0 :   NS_ENSURE_SUCCESS(rv, rv);
         167                 :
         168               0 :   Clear();
         169                 :
         170               0 :   return NS_OK;
         171                 : }
         172                 :
         173                 : nsresult
         174             199 : HashStore::CheckChecksum(nsIFile* aStoreFile)
         175                 : {
         176                 :   // Check for file corruption by
         177                 :   // comparing the stored checksum to actual checksum of data
         178             398 :   nsCAutoString hash;
         179             398 :   nsCAutoString compareHash;
         180                 :   char *data;
         181                 :   PRUint32 read;
         182                 :
         183                 :   PRInt64 fileSize;
         184             199 :   nsresult rv = aStoreFile->GetFileSize(&fileSize);
         185             199 :   NS_ENSURE_SUCCESS(rv, rv);
         186                 :
         187             199 :   if (fileSize < 0) {
         188               0 :     return NS_ERROR_FAILURE;
         189                 :   }
         190                 :
         191             199 :   rv = CalculateChecksum(hash, true);
         192             199 :   NS_ENSURE_SUCCESS(rv, rv);
         193                 :
         194             199 :   compareHash.GetMutableData(&data, hash.Length());
         195                 :
         196             398 :   nsCOMPtr<nsISeekableStream> seekIn = do_QueryInterface(mInputStream);
         197             199 :   rv = seekIn->Seek(nsISeekableStream::NS_SEEK_SET, fileSize-hash.Length());
         198             199 :   NS_ENSURE_SUCCESS(rv, rv);
         199                 :
         200             199 :   rv = mInputStream->Read(data, hash.Length(), &read);
         201             199 :   NS_ENSURE_SUCCESS(rv, rv);
         202             199 :   NS_ASSERTION(read == hash.Length(), "Could not read hash bytes");
         203                 :
         204             199 :   if (!hash.Equals(compareHash)) {
         205               0 :     NS_WARNING("Safebrowing file failed checksum.");
         206               0 :     return NS_ERROR_FAILURE;
         207                 :   }
         208                 :
         209             199 :   return NS_OK;
         210                 : }
         211                 :
         212                 : nsresult
         213             244 : HashStore::Open()
         214                 : {
         215             488 :   nsCOMPtr<nsIFile> storeFile;
         216             244 :   nsresult rv = mStoreDirectory->Clone(getter_AddRefs(storeFile));
         217             244 :   NS_ENSURE_SUCCESS(rv, rv);
         218                 :
         219             244 :   rv = storeFile->AppendNative(mTableName + NS_LITERAL_CSTRING(".sbstore"));
         220             244 :   NS_ENSURE_SUCCESS(rv, rv);
         221                 :
         222             488 :   nsCOMPtr<nsIInputStream> origStream;
         223             244 :   rv = NS_NewLocalFileInputStream(getter_AddRefs(origStream), storeFile,
         224             244 :                                   PR_RDONLY);
         225                 :
         226             244 :   if (NS_FAILED(rv) && rv != NS_ERROR_FILE_NOT_FOUND) {
         227               0 :     Reset();
         228               0 :     return rv;
         229                 :   }
         230                 :
         231             244 :   if (rv == NS_ERROR_FILE_NOT_FOUND) {
         232              45 :     Clear();
         233              45 :     UpdateHeader();
         234              45 :     return NS_OK;
         235                 :   }
         236                 :
         237                 :   PRInt64 fileSize;
         238             199 :   rv = storeFile->GetFileSize(&fileSize);
         239             199 :   NS_ENSURE_SUCCESS(rv, rv);
         240                 :
         241             199 :   rv = NS_NewBufferedInputStream(getter_AddRefs(mInputStream), origStream,
         242             199 :                                  fileSize);
         243             199 :   NS_ENSURE_SUCCESS(rv, rv);
         244                 :
         245             199 :   rv = CheckChecksum(storeFile);
         246             199 :   if (NS_FAILED(rv)) {
         247               0 :     Reset();
         248               0 :     return rv;
         249                 :   }
         250                 :
         251             199 :   rv = ReadHeader();
         252             199 :   if (NS_FAILED(rv)) {
         253               0 :     Reset();
         254               0 :     return rv;
         255                 :   }
         256                 :
         257             199 :   rv = SanityCheck(storeFile);
         258             199 :   if (NS_FAILED(rv)) {
         259               0 :     NS_WARNING("Safebrowsing file failed sanity check. probably out of date.");
         260               0 :     Reset();
         261               0 :     return rv;
         262                 :   }
         263                 :
         264             199 :   rv = ReadChunkNumbers();
         265             199 :   if (NS_FAILED(rv)) {
         266               0 :     Reset();
         267               0 :     return rv;
         268                 :   }
         269                 :
         270             199 :   return NS_OK;
         271                 : }
         272                 :
         273                 : void
         274             232 : HashStore::Clear()
         275                 : {
         276             232 :   mAddChunks.Clear();
         277             232 :   mSubChunks.Clear();
         278             232 :   mAddExpirations.Clear();
         279             232 :   mSubExpirations.Clear();
         280             232 :   mAddPrefixes.Clear();
         281             232 :   mSubPrefixes.Clear();
         282             232 :   mAddCompletes.Clear();
         283             232 :   mSubCompletes.Clear();
         284             232 : }
         285                 :
         286                 : nsresult
         287              97 : HashStore::ReadEntireStore()
         288                 : {
         289              97 :   Clear();
         290                 :
         291              97 :   nsresult rv = ReadHeader();
         292              97 :   NS_ENSURE_SUCCESS(rv, rv);
         293                 :
         294              97 :   rv = ReadChunkNumbers();
         295              97 :   NS_ENSURE_SUCCESS(rv, rv);
         296                 :
         297              97 :   rv = ReadHashes();
         298              97 :   if (NS_FAILED(rv)) {
         299                 :     // we are the only one reading this so it's up to us to detect corruption
         300               0 :     Reset();
         301                 :   }
         302                 :
         303              97 :   return rv;
         304                 : }
         305                 :
         306                 : nsresult
         307             296 : HashStore::ReadHeader()
         308                 : {
         309             296 :   if (!mInputStream) {
         310              45 :     Clear();
         311              45 :     UpdateHeader();
         312              45 :     return NS_OK;
         313                 :   }
         314                 :
         315             502 :   nsCOMPtr<nsISeekableStream> seekable = do_QueryInterface(mInputStream);
         316             251 :   nsresult rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, 0);
         317             251 :   NS_ENSURE_SUCCESS(rv, rv);
         318                 :
         319             251 :   void *buffer = &mHeader;
         320                 :   rv = NS_ReadInputStreamToBuffer(mInputStream,
         321                 :                                   &buffer,
         322             251 :                                   sizeof(Header));
         323             251 :   NS_ENSURE_SUCCESS(rv, rv);
         324                 :
         325             251 :   return NS_OK;
         326                 : }
         327                 :
         328                 : nsresult
         329             199 : HashStore::SanityCheck(nsIFile *storeFile)
         330                 : {
         331             199 :   if (mHeader.magic != STORE_MAGIC || mHeader.version != CURRENT_VERSION) {
         332               0 :     NS_WARNING("Unexpected header data in the store.");
         333               0 :     return NS_ERROR_FAILURE;
         334                 :   }
         335                 :
         336             199 :   return NS_OK;
         337                 : }
         338                 :
         339                 : nsresult
         340             199 : HashStore::CalculateChecksum(nsCAutoString& aChecksum, bool aChecksumPresent)
         341                 : {
         342             199 :   aChecksum.Truncate();
         343                 :
         344             398 :   nsCOMPtr<nsIFile> storeFile;
         345             199 :   nsresult rv = mStoreDirectory->Clone(getter_AddRefs(storeFile));
         346             199 :   NS_ENSURE_SUCCESS(rv, rv);
         347                 :
         348             199 :   rv = storeFile->AppendNative(mTableName + NS_LITERAL_CSTRING(".sbstore"));
         349             199 :   NS_ENSURE_SUCCESS(rv, rv);
         350                 :
         351             398 :   nsCOMPtr<nsIInputStream> hashStream;
         352                 :
         353             199 :   rv = NS_NewLocalFileInputStream(getter_AddRefs(hashStream), storeFile,
         354             199 :                                   PR_RDONLY);
         355                 :
         356             199 :   if (NS_FAILED(rv) && rv != NS_ERROR_FILE_NOT_FOUND) {
         357               0 :     Reset();
         358               0 :     return rv;
         359                 :   }
         360                 :
         361                 :   PRInt64 fileSize;
         362             199 :   rv = storeFile->GetFileSize(&fileSize);
         363             199 :   NS_ENSURE_SUCCESS(rv, rv);
         364                 :
         365             199 :   if (fileSize < 0) {
         366               0 :     return NS_ERROR_FAILURE;
         367                 :   }
         368                 :
         369             398 :   nsCOMPtr<nsICryptoHash> hash = do_CreateInstance(NS_CRYPTO_HASH_CONTRACTID, &rv);
         370             199 :   NS_ENSURE_SUCCESS(rv, rv);
         371                 :
         372                 :   // Size of MD5 hash in bytes
         373             199 :   const uint32 CHECKSUM_SIZE = 16;
         374                 :
         375             199 :   rv = hash->Init(nsICryptoHash::MD5);
         376             199 :   NS_ENSURE_SUCCESS(rv, rv);
         377                 :
         378             199 :   if (!aChecksumPresent) {
         379                 :     // Hash entire file
         380               0 :     rv = hash->UpdateFromStream(hashStream, PR_UINT32_MAX);
         381                 :   } else {
         382                 :     // Hash everything but last checksum bytes
         383             199 :     rv = hash->UpdateFromStream(hashStream, fileSize-CHECKSUM_SIZE);
         384                 :   }
         385             199 :   NS_ENSURE_SUCCESS(rv, rv);
         386                 :
         387             199 :   rv = hash->Finish(PR_FALSE, aChecksum);
         388             199 :   NS_ENSURE_SUCCESS(rv, rv);
         389                 :
         390             199 :   return NS_OK;
         391                 : }
         392                 :
         393                 : void
         394             187 : HashStore::UpdateHeader()
         395                 : {
         396             187 :   mHeader.magic = STORE_MAGIC;
         397             187 :   mHeader.version = CURRENT_VERSION;
         398                 :
         399             187 :   mHeader.numAddChunks = mAddChunks.Length();
         400             187 :   mHeader.numSubChunks = mSubChunks.Length();
         401             187 :   mHeader.numAddPrefixes = mAddPrefixes.Length();
         402             187 :   mHeader.numSubPrefixes = mSubPrefixes.Length();
         403             187 :   mHeader.numAddCompletes = mAddCompletes.Length();
         404             187 :   mHeader.numSubCompletes = mSubCompletes.Length();
         405             187 : }
         406                 :
         407                 : nsresult
         408             296 : HashStore::ReadChunkNumbers()
         409                 : {
         410             296 :   if (!mInputStream) {
         411              45 :     LOG(("Clearing."));
         412              45 :     Clear();
         413              45 :     return NS_OK;
         414                 :   }
         415                 :
         416             502 :   nsCOMPtr<nsISeekableStream> seekable = do_QueryInterface(mInputStream);
         417             251 :   nsresult rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET,
         418             251 :                                sizeof(Header));
         419                 :
         420             251 :   rv = mAddChunks.Read(mInputStream, mHeader.numAddChunks);
         421             251 :   NS_ENSURE_SUCCESS(rv, rv);
         422             251 :   NS_ASSERTION(mAddChunks.Length() == mHeader.numAddChunks, "Read the right amount of add chunks.");
         423                 :
         424             251 :   rv = mSubChunks.Read(mInputStream, mHeader.numSubChunks);
         425             251 :   NS_ENSURE_SUCCESS(rv, rv);
         426             251 :   NS_ASSERTION(mSubChunks.Length() == mHeader.numSubChunks, "Read the right amount of sub chunks.");
         427                 :
         428             251 :   return NS_OK;
         429                 : }
         430                 :
         431                 : nsresult
         432              97 : HashStore::ReadHashes()
         433                 : {
         434              97 :   if (!mInputStream) {
         435              45 :     return NS_OK;
         436                 :   }
         437                 :
         438             104 :   nsCOMPtr<nsISeekableStream> seekable = do_QueryInterface(mInputStream);
         439                 :
         440              52 :   uint32 offset = sizeof(Header);
         441              52 :   offset += (mHeader.numAddChunks + mHeader.numSubChunks) * sizeof(uint32);
         442              52 :   nsresult rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, offset);
         443                 :
         444              52 :   rv = ReadAddPrefixes();
         445              52 :   NS_ENSURE_SUCCESS(rv, rv);
         446                 :
         447              52 :   rv = ReadSubPrefixes();
         448              52 :   NS_ENSURE_SUCCESS(rv, rv);
         449                 :
         450              52 :   rv = ReadTArray(mInputStream, &mAddCompletes, mHeader.numAddCompletes);
         451              52 :   NS_ENSURE_SUCCESS(rv, rv);
         452                 :
         453              52 :   rv = ReadTArray(mInputStream, &mSubCompletes, mHeader.numSubCompletes);
         454              52 :   NS_ENSURE_SUCCESS(rv, rv);
         455                 :
         456              52 :   return NS_OK;
         457                 : }
         458                 :
         459                 : nsresult
         460              97 : HashStore::BeginUpdate()
         461                 : {
         462              97 :   mInUpdate = true;
         463                 :
         464              97 :   nsresult rv = ReadEntireStore();
         465              97 :   NS_ENSURE_SUCCESS(rv, rv);
         466                 :
         467              97 :   return NS_OK;
         468                 : }
         469                 :
         470                 : template<class T>
         471                 : static nsresult
         472             488 : Merge(ChunkSet* aStoreChunks,
         473                 :       nsTArray<T>* aStorePrefixes,
         474                 :       ChunkSet& aUpdateChunks,
         475                 :       nsTArray<T>& aUpdatePrefixes)
         476                 : {
         477             488 :   EntrySort(aUpdatePrefixes);
         478                 :
         479             488 :   T* updateIter = aUpdatePrefixes.Elements();
         480             488 :   T* updateEnd = aUpdatePrefixes.Elements() + aUpdatePrefixes.Length();
         481                 :
         482             488 :   T* storeIter = aStorePrefixes->Elements();
         483             488 :   T* storeEnd = aStorePrefixes->Elements() + aStorePrefixes->Length();
         484                 :
         485                 :   // use a separate array so we can keep the iterators valid
         486                 :   // if the nsTArray grows
         487             976 :   nsTArray<T> adds;
         488                 :
         489             695 :   for (; updateIter != updateEnd; updateIter++) {
         490                 :     // XXX: binary search for insertion point might be faster in common
         491                 :     // case?
         492             485 :     while (storeIter < storeEnd && (storeIter->Compare(*updateIter) < 0)) {
         493                 :       // skip forward to matching element (or not...)
         494              71 :       storeIter++;
         495                 :     }
         496                 :     // no match, add
         497             207 :     if (storeIter == storeEnd
         498                 :         || storeIter->Compare(*updateIter) != 0) {
         499             198 :       if (!adds.AppendElement(*updateIter))
         500               0 :         return NS_ERROR_OUT_OF_MEMORY;
         501                 :     }
         502                 :   }
         503                 :
         504                 :   // chunks can be empty, but we should still report we have them
         505                 :   // to make the chunkranges continuous
         506             488 :   aStoreChunks->Merge(aUpdateChunks);
         507                 :
         508             488 :   aStorePrefixes->AppendElements(adds);
         509             488 :   EntrySort(*aStorePrefixes);
         510                 :
         511             488 :   return NS_OK;
         512                 : }
         513                 :
         514                 : nsresult
         515             122 : HashStore::ApplyUpdate(TableUpdate &update)
         516                 : {
         517             122 :   nsresult rv = mAddExpirations.Merge(update.AddExpirations());
         518             122 :   NS_ENSURE_SUCCESS(rv, rv);
         519                 :
         520             122 :   rv = mSubExpirations.Merge(update.SubExpirations());
         521             122 :   NS_ENSURE_SUCCESS(rv, rv);
         522                 :
         523             122 :   rv = Expire();
         524             122 :   NS_ENSURE_SUCCESS(rv, rv);
         525                 :
         526                 :   rv = Merge(&mAddChunks, &mAddPrefixes,
         527             122 :              update.AddChunks(), update.AddPrefixes());
         528             122 :   NS_ENSURE_SUCCESS(rv, rv);
         529                 :
         530                 :   rv = Merge(&mAddChunks, &mAddCompletes,
         531             122 :              update.AddChunks(), update.AddCompletes());
         532             122 :   NS_ENSURE_SUCCESS(rv, rv);
         533                 :
         534                 :   rv = Merge(&mSubChunks, &mSubPrefixes,
         535             122 :              update.SubChunks(), update.SubPrefixes());
         536             122 :   NS_ENSURE_SUCCESS(rv, rv);
         537                 :
         538                 :   rv = Merge(&mSubChunks, &mSubCompletes,
         539             122 :              update.SubChunks(), update.SubCompletes());
         540             122 :   NS_ENSURE_SUCCESS(rv, rv);
         541                 :
         542             122 :   return NS_OK;
         543                 : }
         544                 :
         545                 : nsresult
         546              97 : HashStore::Rebuild()
         547                 : {
         548              97 :   NS_ASSERTION(mInUpdate, "Must be in update to rebuild.");
         549                 :
         550              97 :   nsresult rv = ProcessSubs();
         551              97 :   NS_ENSURE_SUCCESS(rv, rv);
         552                 :
         553              97 :   UpdateHeader();
         554                 :
         555              97 :   return NS_OK;
         556                 : }
         557                 :
         558                 : template<class T>
         559                 : static void
         560             682 : ExpireEntries(nsTArray<T>* aEntries, ChunkSet& aExpirations)
         561                 : {
         562             682 :   T* addIter = aEntries->Elements();
         563             682 :   T* end = aEntries->Elements() + aEntries->Length();
         564                 :
         565            1112 :   for (T *iter = addIter; iter != end; iter++) {
         566             430 :     if (!aExpirations.Has(iter->Chunk())) {
         567             406 :       *addIter = *iter;
         568             406 :       addIter++;
         569                 :     }
         570                 :   }
         571                 :
         572             682 :   aEntries->SetLength(addIter - aEntries->Elements());
         573             682 : }
         574                 :
         575                 : nsresult
         576             122 : HashStore::Expire()
         577                 : {
         578             122 :   ExpireEntries(&mAddPrefixes, mAddExpirations);
         579             122 :   ExpireEntries(&mAddCompletes, mAddExpirations);
         580             122 :   ExpireEntries(&mSubPrefixes, mSubExpirations);
         581             122 :   ExpireEntries(&mSubCompletes, mSubExpirations);
         582                 :
         583             122 :   mAddChunks.Remove(mAddExpirations);
         584             122 :   mSubChunks.Remove(mSubExpirations);
         585                 :
         586             122 :   mAddExpirations.Clear();
         587             122 :   mSubExpirations.Clear();
         588                 :
         589             122 :   return NS_OK;
         590                 : }
         591                 :
         592                 : template<class T>
         593            1164 : nsresult DeflateWriteTArray(nsIOutputStream* aStream, nsTArray<T>& aIn)
         594                 : {
         595            1164 :   uLongf insize = aIn.Length() * sizeof(T);
         596            1164 :   uLongf outsize = compressBound(insize);
         597            2328 :   nsTArray<char> outBuff;
         598            1164 :   outBuff.SetLength(outsize);
         599                 :
         600                 :   int zerr = compress(reinterpret_cast<Bytef*>(outBuff.Elements()),
         601                 :                       &outsize,
         602                 :                       reinterpret_cast<const Bytef*>(aIn.Elements()),
         603            1164 :                       insize);
         604            1164 :   if (zerr != Z_OK) {
         605               0 :     return NS_ERROR_FAILURE;
         606                 :   }
         607            1164 :   LOG(("DeflateWriteTArray: %d in %d out", insize, outsize));
         608                 :
         609            1164 :   outBuff.TruncateLength(outsize);
         610                 :
         611                 :   // Length of compressed data stream
         612            1164 :   PRUint32 dataLen = outBuff.Length();
         613                 :   PRUint32 written;
         614            1164 :   nsresult rv = aStream->Write(reinterpret_cast<char*>(&dataLen), sizeof(dataLen), &written);
         615            1164 :   NS_ENSURE_SUCCESS(rv, rv);
         616                 :
         617            1164 :   NS_ASSERTION(written == sizeof(dataLen), "Error writing deflate length");
         618                 :
         619                 :   // Store to stream
         620            1164 :   rv = WriteTArray(aStream, outBuff);
         621            1164 :   NS_ENSURE_SUCCESS(rv, rv);
         622                 :
         623            1164 :   return NS_OK;
         624                 : }
         625                 :
         626                 : template<class T>
         627             624 : nsresult InflateReadTArray(nsIInputStream* aStream, nsTArray<T>* aOut,
         628                 :                            PRUint32 aExpectedSize)
         629                 : {
         630                 :
         631                 :   PRUint32 inLen;
         632                 :   PRUint32 read;
         633             624 :   nsresult rv = aStream->Read(reinterpret_cast<char*>(&inLen), sizeof(inLen), &read);
         634             624 :   NS_ENSURE_SUCCESS(rv, rv);
         635                 :
         636             624 :   NS_ASSERTION(read == sizeof(inLen), "Error reading inflate length");
         637                 :
         638            1248 :   nsTArray<char> inBuff;
         639             624 :   inBuff.SetLength(inLen);
         640                 :
         641             624 :   rv = ReadTArray(aStream, &inBuff, inLen);
         642             624 :   NS_ENSURE_SUCCESS(rv, rv);
         643                 :
         644             624 :   uLongf insize = inLen;
         645             624 :   uLongf outsize = aExpectedSize * sizeof(T);
         646             624 :   aOut->SetLength(aExpectedSize);
         647                 :
         648                 :   int zerr = uncompress(reinterpret_cast<Bytef*>(aOut->Elements()),
         649                 :                         &outsize,
         650                 :                         reinterpret_cast<const Bytef*>(inBuff.Elements()),
         651             624 :                         insize);
         652             624 :   if (zerr != Z_OK) {
         653               0 :     return NS_ERROR_FAILURE;
         654                 :   }
         655             624 :   LOG(("InflateReadTArray: %d in %d out", insize, outsize));
         656                 :
         657             624 :   NS_ASSERTION(outsize == aExpectedSize * sizeof(T), "Decompression size mismatch");
         658                 :
         659             624 :   return NS_OK;
         660                 : }
         661                 :
         662                 : static nsresult
         663             388 : ByteSliceWrite(nsIOutputStream* aOut, nsTArray<PRUint32>& aData)
         664                 : {
         665             776 :   nsTArray<PRUint8> slice1;
         666             776 :   nsTArray<PRUint8> slice2;
         667             776 :   nsTArray<PRUint8> slice3;
         668             776 :   nsTArray<PRUint8> slice4;
         669             388 :   PRUint32 count = aData.Length();
         670                 :
         671             388 :   slice1.SetCapacity(count);
         672             388 :   slice2.SetCapacity(count);
         673             388 :   slice3.SetCapacity(count);
         674             388 :   slice4.SetCapacity(count);
         675                 :
         676             495 :   for (PRUint32 i = 0; i < count; i++) {
         677             107 :     slice1.AppendElement( aData[i] >> 24);
         678             107 :     slice2.AppendElement((aData[i] >> 16) & 0xFF);
         679             107 :     slice3.AppendElement((aData[i] >>  8) & 0xFF);
         680             107 :     slice4.AppendElement( aData[i]        & 0xFF);
         681                 :   }
         682                 :
         683             388 :   nsresult rv = DeflateWriteTArray(aOut, slice1);
         684             388 :   NS_ENSURE_SUCCESS(rv, rv);
         685             388 :   rv = DeflateWriteTArray(aOut, slice2);
         686             388 :   NS_ENSURE_SUCCESS(rv, rv);
         687             388 :   rv = DeflateWriteTArray(aOut, slice3);
         688             388 :   NS_ENSURE_SUCCESS(rv, rv);
         689                 :   // The LSB slice is generally uncompressible, don't bother
         690                 :   // compressing it.
         691             388 :   rv = WriteTArray(aOut, slice4);
         692             388 :   NS_ENSURE_SUCCESS(rv, rv);
         693                 :
         694             388 :   return NS_OK;
         695                 : }
         696                 :
         697                 : static nsresult
         698             208 : ByteSliceRead(nsIInputStream* aInStream, nsTArray<PRUint32>* aData, PRUint32 count)
         699                 : {
         700             416 :   nsTArray<PRUint8> slice1;
         701             416 :   nsTArray<PRUint8> slice2;
         702             416 :   nsTArray<PRUint8> slice3;
         703             416 :   nsTArray<PRUint8> slice4;
         704                 :
         705             208 :   nsresult rv = InflateReadTArray(aInStream, &slice1, count);
         706             208 :   NS_ENSURE_SUCCESS(rv, rv);
         707                 :
         708             208 :   rv = InflateReadTArray(aInStream, &slice2, count);
         709             208 :   NS_ENSURE_SUCCESS(rv, rv);
         710                 :
         711             208 :   rv = InflateReadTArray(aInStream, &slice3, count);
         712             208 :   NS_ENSURE_SUCCESS(rv, rv);
         713                 :
         714             208 :   rv = ReadTArray(aInStream, &slice4, count);
         715             208 :   NS_ENSURE_SUCCESS(rv, rv);
         716                 :
         717             208 :   aData->SetCapacity(count);
         718                 :
         719             272 :   for (uint32 i = 0; i < count; i++) {
         720             128 :     aData->AppendElement((slice1[i] << 24) | (slice2[i] << 16)
         721             128 :                          | (slice3[i] << 8) | (slice4[i]));
         722                 :   }
         723                 :
         724             208 :   return NS_OK;
         725                 : }
         726                 :
         727                 : nsresult
         728              52 : HashStore::ReadAddPrefixes()
         729                 : {
         730             104 :   nsTArray<PRUint32> chunks;
         731              52 :   PRUint32 count = mHeader.numAddPrefixes;
         732                 :
         733              52 :   nsresult rv = ByteSliceRead(mInputStream, &chunks, count);
         734              52 :   NS_ENSURE_SUCCESS(rv, rv);
         735                 :
         736              52 :   mAddPrefixes.SetCapacity(count);
         737             116 :   for (PRUint32 i = 0; i < count; i++) {
         738              64 :     AddPrefix *add = mAddPrefixes.AppendElement();
         739              64 :     add->prefix.FromUint32(0);
         740              64 :     add->addChunk = chunks[i];
         741                 :   }
         742                 :
         743              52 :   return NS_OK;
         744                 : }
         745                 :
         746                 : nsresult
         747              52 : HashStore::ReadSubPrefixes()
         748                 : {
         749             104 :   nsTArray<PRUint32> addchunks;
         750             104 :   nsTArray<PRUint32> subchunks;
         751             104 :   nsTArray<PRUint32> prefixes;
         752              52 :   PRUint32 count = mHeader.numSubPrefixes;
         753                 :
         754              52 :   nsresult rv = ByteSliceRead(mInputStream, &addchunks, count);
         755              52 :   NS_ENSURE_SUCCESS(rv, rv);
         756                 :
         757              52 :   rv = ByteSliceRead(mInputStream, &subchunks, count);
         758              52 :   NS_ENSURE_SUCCESS(rv, rv);
         759                 :
         760              52 :   rv = ByteSliceRead(mInputStream, &prefixes, count);
         761              52 :   NS_ENSURE_SUCCESS(rv, rv);
         762                 :
         763              52 :   mSubPrefixes.SetCapacity(count);
         764              52 :   for (uint32 i = 0; i < count; i++) {
         765               0 :     SubPrefix *sub = mSubPrefixes.AppendElement();
         766               0 :     sub->addChunk = addchunks[i];
         767               0 :     sub->prefix.FromUint32(prefixes[i]);
         768               0 :     sub->subChunk = subchunks[i];
         769                 :   }
         770                 :
         771              52 :   return NS_OK;
         772                 : }
         773                 :
         774                 : // Split up PrefixArray back into the constituents
         775                 : nsresult
         776              97 : HashStore::WriteAddPrefixes(nsIOutputStream* aOut)
         777                 : {
         778             194 :   nsTArray<PRUint32> chunks;
         779              97 :   PRUint32 count = mAddPrefixes.Length();
         780              97 :   chunks.SetCapacity(count);
         781                 :
         782             204 :   for (uint32 i = 0; i < count; i++) {
         783             107 :     chunks.AppendElement(mAddPrefixes[i].Chunk());
         784                 :   }
         785                 :
         786              97 :   nsresult rv = ByteSliceWrite(aOut, chunks);
         787              97 :   NS_ENSURE_SUCCESS(rv, rv);
         788                 :
         789              97 :   return NS_OK;
         790                 : }
         791                 :
         792                 : nsresult
         793              97 : HashStore::WriteSubPrefixes(nsIOutputStream* aOut)
         794                 : {
         795             194 :   nsTArray<PRUint32> addchunks;
         796             194 :   nsTArray<PRUint32> subchunks;
         797             194 :   nsTArray<PRUint32> prefixes;
         798              97 :   PRUint32 count = mSubPrefixes.Length();
         799              97 :   addchunks.SetCapacity(count);
         800              97 :   subchunks.SetCapacity(count);
         801              97 :   prefixes.SetCapacity(count);
         802                 :
         803              97 :   for (uint32 i = 0; i < count; i++) {
         804               0 :     addchunks.AppendElement(mSubPrefixes[i].AddChunk());
         805               0 :     prefixes.AppendElement(mSubPrefixes[i].PrefixHash().ToUint32());
         806               0 :     subchunks.AppendElement(mSubPrefixes[i].Chunk());
         807                 :   }
         808                 :
         809              97 :   nsresult rv = ByteSliceWrite(aOut, addchunks);
         810              97 :   NS_ENSURE_SUCCESS(rv, rv);
         811                 :
         812              97 :   rv = ByteSliceWrite(aOut, subchunks);
         813              97 :   NS_ENSURE_SUCCESS(rv, rv);
         814                 :
         815              97 :   rv = ByteSliceWrite(aOut, prefixes);
         816              97 :   NS_ENSURE_SUCCESS(rv, rv);
         817                 :
         818              97 :   return NS_OK;
         819                 : }
         820                 :
         821                 : nsresult
         822              97 : HashStore::WriteFile()
         823                 : {
         824             194 :   nsCOMPtr<nsIFile> storeFile;
         825              97 :   nsresult rv = mStoreDirectory->Clone(getter_AddRefs(storeFile));
         826              97 :   NS_ENSURE_SUCCESS(rv, rv);
         827              97 :   rv = storeFile->AppendNative(mTableName + NS_LITERAL_CSTRING(".sbstore"));
         828              97 :   NS_ENSURE_SUCCESS(rv, rv);
         829                 :
         830                 :   // Need to close the inputstream here *before* rewriting its file.
         831                 :   // Windows will fail with an access violation if we don't.
         832              97 :   if (mInputStream) {
         833              52 :     rv = mInputStream->Close();
         834              52 :     NS_ENSURE_SUCCESS(rv, rv);
         835                 :   }
         836                 :
         837             194 :   nsCOMPtr<nsIOutputStream> out;
         838              97 :   rv = NS_NewCheckSummedOutputStream(getter_AddRefs(out), storeFile,
         839              97 :                                      PR_WRONLY | PR_TRUNCATE | PR_CREATE_FILE);
         840              97 :   NS_ENSURE_SUCCESS(rv, rv);
         841                 :
         842                 :   PRUint32 written;
         843              97 :   rv = out->Write(reinterpret_cast<char*>(&mHeader), sizeof(mHeader), &written);
         844              97 :   NS_ENSURE_SUCCESS(rv, rv);
         845                 :
         846                 :   // Write chunk numbers...
         847              97 :   rv = mAddChunks.Write(out);
         848              97 :   NS_ENSURE_SUCCESS(rv, rv);
         849                 :
         850              97 :   rv = mSubChunks.Write(out);
         851              97 :   NS_ENSURE_SUCCESS(rv, rv);
         852                 :
         853                 :   // Write hashes..
         854              97 :   rv = WriteAddPrefixes(out);
         855              97 :   NS_ENSURE_SUCCESS(rv, rv);
         856                 :
         857              97 :   rv = WriteSubPrefixes(out);
         858              97 :   NS_ENSURE_SUCCESS(rv, rv);
         859                 :
         860              97 :   rv = WriteTArray(out, mAddCompletes);
         861              97 :   NS_ENSURE_SUCCESS(rv, rv);
         862                 :
         863              97 :   rv = WriteTArray(out, mSubCompletes);
         864              97 :   NS_ENSURE_SUCCESS(rv, rv);
         865                 :
         866             194 :   nsCOMPtr<nsISafeOutputStream> safeOut = do_QueryInterface(out, &rv);
         867              97 :   NS_ENSURE_SUCCESS(rv, rv);
         868                 :
         869              97 :   rv = safeOut->Finish();
         870              97 :   NS_ENSURE_SUCCESS(rv, rv);
         871                 :
         872                 :   PRInt64 fileSize;
         873              97 :   rv = storeFile->GetFileSize(&fileSize);
         874              97 :   NS_ENSURE_SUCCESS(rv, rv);
         875                 :
         876                 :   // Reopen the file now that we've rewritten it.
         877             194 :   nsCOMPtr<nsIInputStream> origStream;
         878              97 :   rv = NS_NewLocalFileInputStream(getter_AddRefs(origStream), storeFile,
         879              97 :                                   PR_RDONLY);
         880              97 :   NS_ENSURE_SUCCESS(rv, rv);
         881                 :
         882              97 :   rv = NS_NewBufferedInputStream(getter_AddRefs(mInputStream), origStream,
         883              97 :                                  fileSize);
         884              97 :   NS_ENSURE_SUCCESS(rv, rv);
         885                 :
         886              97 :   return NS_OK;
         887                 : }
         888                 :
         889                 : nsresult
         890              97 : HashStore::FinishUpdate()
         891                 : {
         892                 :   // Drop add/sub data, it's only used during updates.
         893              97 :   mAddPrefixes.Clear();
         894              97 :   mSubPrefixes.Clear();
         895              97 :   mAddCompletes.Clear();
         896              97 :   mSubCompletes.Clear();
         897                 :
         898              97 :   return NS_OK;
         899                 : }
         900                 :
         901                 : template <class T>
         902                 : static void
         903             582 : Erase(nsTArray<T>* array, T* iterStart, T* iterEnd)
         904                 : {
         905             582 :   uint32 start = iterStart - array->Elements();
         906             582 :   uint32 count = iterEnd - iterStart;
         907                 :
         908             582 :   if (count > 0) {
         909              27 :     array->RemoveElementsAt(start, count);
         910                 :   }
         911             582 : }
         912                 :
         913                 : // Find items matching between |subs| and |adds|, and remove them,
         914                 : // recording the item from |adds| in |adds_removed|.  To minimize
         915                 : // copies, the inputs are processing in parallel, so |subs| and |adds|
         916                 : // should be compatibly ordered (either by SBAddPrefixLess or
         917                 : // SBAddPrefixHashLess).
         918                 : //
         919                 : // |predAS| provides add < sub, |predSA| provides sub < add, for the
         920                 : // tightest compare appropriate (see calls in SBProcessSubs).
         921                 : template<class TSub, class TAdd>
         922                 : static void
         923             194 : KnockoutSubs(nsTArray<TSub>* aSubs, nsTArray<TAdd>* aAdds)
         924                 : {
         925                 :   // Keep a pair of output iterators for writing kept items.  Due to
         926                 :   // deletions, these may lag the main iterators.  Using erase() on
         927                 :   // individual items would result in O(N^2) copies.  Using a list
         928                 :   // would work around that, at double or triple the memory cost.
         929             194 :   TAdd* addOut = aAdds->Elements();
         930             194 :   TAdd* addIter = aAdds->Elements();
         931                 :
         932             194 :   TSub* subOut = aSubs->Elements();
         933             194 :   TSub* subIter = aSubs->Elements();
         934                 :
         935             194 :   TAdd* addEnd = addIter + aAdds->Length();
         936             194 :   TSub* subEnd = subIter + aSubs->Length();
         937                 :
         938             425 :   while (addIter != addEnd && subIter != subEnd) {
         939                 :     // additer compare, so it compares on add chunk
         940              37 :     int32 cmp = addIter->Compare(*subIter);
         941              37 :     if (cmp > 0) {
         942                 :       // If |*sub_iter| < |*add_iter|, retain the sub.
         943               9 :       *subOut = *subIter;
         944               9 :       ++subOut;
         945               9 :       ++subIter;
         946              28 :     } else if (cmp < 0) {
         947                 :       // If |*add_iter| < |*sub_iter|, retain the add.
         948              13 :       *addOut = *addIter;
         949              13 :       ++addOut;
         950              13 :       ++addIter;
         951                 :     } else {
         952                 :       // Drop equal items
         953              15 :       ++addIter;
         954              15 :       ++subIter;
         955                 :     }
         956                 :   }
         957                 :
         958             194 :   Erase(aAdds, addOut, addIter);
         959             194 :   Erase(aSubs, subOut, subIter);
         960             194 : }
         961                 :
         962                 : // Remove items in |removes| from |fullHashes|.  |fullHashes| and
         963                 : // |removes| should be ordered by SBAddPrefix component.
         964                 : template <class T>
         965                 : static void
         966             194 : RemoveMatchingPrefixes(const SubPrefixArray& aSubs, nsTArray<T>* aFullHashes)
         967                 : {
         968                 :   // Where to store kept items.
         969             194 :   T* out = aFullHashes->Elements();
         970             194 :   T* hashIter = out;
         971             194 :   T* hashEnd = aFullHashes->Elements() + aFullHashes->Length();
         972                 :
         973             194 :   SubPrefix const * removeIter = aSubs.Elements();
         974             194 :   SubPrefix const * removeEnd = aSubs.Elements() + aSubs.Length();
         975                 :
         976             389 :   while (hashIter != hashEnd && removeIter != removeEnd) {
         977               1 :     int32 cmp = removeIter->CompareAlt(*hashIter);
         978               1 :     if (cmp > 0) {
         979                 :       // Keep items less than |*removeIter|.
         980               0 :       *out = *hashIter;
         981               0 :       ++out;
         982               0 :       ++hashIter;
         983               1 :     } else if (cmp < 0) {
         984                 :       // No hit for |*removeIter|, bump it forward.
         985               0 :       ++removeIter;
         986                 :     } else {
         987                 :       // Drop equal items, there may be multiple hits.
         988               1 :       do {
         989               1 :         ++hashIter;
         990                 :       } while (hashIter != hashEnd &&
         991                 :                !(removeIter->CompareAlt(*hashIter) < 0));
         992               1 :       ++removeIter;
         993                 :     }
         994                 :   }
         995             194 :   Erase(aFullHashes, out, hashIter);
         996             194 : }
         997                 :
         998                 : nsresult
         999              97 : HashStore::ProcessSubs()
        1000                 : {
        1001              97 :   EntrySort(mAddPrefixes);
        1002              97 :   EntrySort(mSubPrefixes);
        1003              97 :   EntrySort(mAddCompletes);
        1004              97 :   EntrySort(mSubCompletes);
        1005                 :
        1006              97 :   KnockoutSubs(&mSubPrefixes, &mAddPrefixes);
        1007                 :
        1008              97 :   RemoveMatchingPrefixes(mSubPrefixes, &mAddCompletes);
        1009              97 :   RemoveMatchingPrefixes(mSubPrefixes, &mSubCompletes);
        1010                 :
        1011              97 :   KnockoutSubs(&mSubCompletes, &mAddCompletes);
        1012                 :
        1013                 :   // Clean up temporary subs used for knocking out completes
        1014             194 :   ChunkSet dummyChunks;
        1015              97 :   dummyChunks.Set(0);
        1016              97 :   ExpireEntries(&mSubPrefixes, dummyChunks);
        1017              97 :   ExpireEntries(&mSubCompletes, dummyChunks);
        1018              97 :   mSubChunks.Remove(dummyChunks);
        1019                 :
        1020              97 :   return NS_OK;
        1021                 : }
        1022                 :
        1023                 : nsresult
        1024              97 : HashStore::AugmentAdds(const nsTArray<PRUint32>& aPrefixes)
        1025                 : {
        1026              97 :   uint32 cnt = aPrefixes.Length();
        1027              97 :   if (cnt != mAddPrefixes.Length()) {
        1028               0 :     LOG(("Amount of prefixes in cache not consistent with store (%d vs %d)",
        1029                 :          aPrefixes.Length(), mAddPrefixes.Length()));
        1030               0 :     return NS_ERROR_FAILURE;
        1031                 :   }
        1032             161 :   for (uint32 i = 0; i < cnt; i++) {
        1033              64 :     mAddPrefixes[i].prefix.FromUint32(aPrefixes[i]);
        1034                 :   }
        1035              97 :   return NS_OK;
        1036                 : }
        1037                 :
        1038                 : }
        1039                 : }

Generated by: LCOV version 1.7