toolkit/components/url-classifier/nsUrlClassifierPrefixSet.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.

michael@0 1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
michael@0 3 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 #include "nsAutoPtr.h"
michael@0 8 #include "nsCOMPtr.h"
michael@0 9 #include "nsDebug.h"
michael@0 10 #include "nsPrintfCString.h"
michael@0 11 #include "nsTArray.h"
michael@0 12 #include "nsString.h"
michael@0 13 #include "nsUrlClassifierPrefixSet.h"
michael@0 14 #include "nsIUrlClassifierPrefixSet.h"
michael@0 15 #include "nsIRandomGenerator.h"
michael@0 16 #include "nsIFile.h"
michael@0 17 #include "nsToolkitCompsCID.h"
michael@0 18 #include "nsTArray.h"
michael@0 19 #include "nsThreadUtils.h"
michael@0 20 #include "mozilla/MemoryReporting.h"
michael@0 21 #include "mozilla/Mutex.h"
michael@0 22 #include "mozilla/Telemetry.h"
michael@0 23 #include "mozilla/FileUtils.h"
michael@0 24 #include "prlog.h"
michael@0 25
michael@0 26 using namespace mozilla;
michael@0 27
michael@0 28 // NSPR_LOG_MODULES=UrlClassifierPrefixSet:5
michael@0 29 #if defined(PR_LOGGING)
michael@0 30 static const PRLogModuleInfo *gUrlClassifierPrefixSetLog = nullptr;
michael@0 31 #define LOG(args) PR_LOG(gUrlClassifierPrefixSetLog, PR_LOG_DEBUG, args)
michael@0 32 #define LOG_ENABLED() PR_LOG_TEST(gUrlClassifierPrefixSetLog, 4)
michael@0 33 #else
michael@0 34 #define LOG(args)
michael@0 35 #define LOG_ENABLED() (false)
michael@0 36 #endif
michael@0 37
michael@0 38 NS_IMPL_ISUPPORTS(
michael@0 39 nsUrlClassifierPrefixSet, nsIUrlClassifierPrefixSet, nsIMemoryReporter)
michael@0 40
michael@0 41 nsUrlClassifierPrefixSet::nsUrlClassifierPrefixSet()
michael@0 42 : mHasPrefixes(false)
michael@0 43 , mMemoryReportPath()
michael@0 44 {
michael@0 45 #if defined(PR_LOGGING)
michael@0 46 if (!gUrlClassifierPrefixSetLog)
michael@0 47 gUrlClassifierPrefixSetLog = PR_NewLogModule("UrlClassifierPrefixSet");
michael@0 48 #endif
michael@0 49 }
michael@0 50
michael@0 51 NS_IMETHODIMP
michael@0 52 nsUrlClassifierPrefixSet::Init(const nsACString& aName)
michael@0 53 {
michael@0 54 mMemoryReportPath =
michael@0 55 nsPrintfCString(
michael@0 56 "explicit/storage/prefix-set/%s",
michael@0 57 (!aName.IsEmpty() ? PromiseFlatCString(aName).get() : "?!")
michael@0 58 );
michael@0 59
michael@0 60 RegisterWeakMemoryReporter(this);
michael@0 61
michael@0 62 return NS_OK;
michael@0 63 }
michael@0 64
michael@0 65 nsUrlClassifierPrefixSet::~nsUrlClassifierPrefixSet()
michael@0 66 {
michael@0 67 UnregisterWeakMemoryReporter(this);
michael@0 68 }
michael@0 69
michael@0 70 NS_IMETHODIMP
michael@0 71 nsUrlClassifierPrefixSet::SetPrefixes(const uint32_t* aArray, uint32_t aLength)
michael@0 72 {
michael@0 73 if (aLength <= 0) {
michael@0 74 if (mHasPrefixes) {
michael@0 75 LOG(("Clearing PrefixSet"));
michael@0 76 mDeltas.Clear();
michael@0 77 mIndexPrefixes.Clear();
michael@0 78 mIndexStarts.Clear();
michael@0 79 mHasPrefixes = false;
michael@0 80 }
michael@0 81 } else {
michael@0 82 return MakePrefixSet(aArray, aLength);
michael@0 83 }
michael@0 84
michael@0 85 return NS_OK;
michael@0 86 }
michael@0 87
michael@0 88 nsresult
michael@0 89 nsUrlClassifierPrefixSet::MakePrefixSet(const uint32_t* aPrefixes, uint32_t aLength)
michael@0 90 {
michael@0 91 if (aLength == 0) {
michael@0 92 return NS_OK;
michael@0 93 }
michael@0 94
michael@0 95 #ifdef DEBUG
michael@0 96 for (uint32_t i = 1; i < aLength; i++) {
michael@0 97 MOZ_ASSERT(aPrefixes[i] >= aPrefixes[i-1]);
michael@0 98 }
michael@0 99 #endif
michael@0 100
michael@0 101 mIndexPrefixes.Clear();
michael@0 102 mIndexStarts.Clear();
michael@0 103 mDeltas.Clear();
michael@0 104
michael@0 105 mIndexPrefixes.AppendElement(aPrefixes[0]);
michael@0 106 mIndexStarts.AppendElement(mDeltas.Length());
michael@0 107
michael@0 108 uint32_t numOfDeltas = 0;
michael@0 109 uint32_t currentItem = aPrefixes[0];
michael@0 110 for (uint32_t i = 1; i < aLength; i++) {
michael@0 111 if ((numOfDeltas >= DELTAS_LIMIT) ||
michael@0 112 (aPrefixes[i] - currentItem >= MAX_INDEX_DIFF)) {
michael@0 113 mIndexStarts.AppendElement(mDeltas.Length());
michael@0 114 mIndexPrefixes.AppendElement(aPrefixes[i]);
michael@0 115 numOfDeltas = 0;
michael@0 116 } else {
michael@0 117 uint16_t delta = aPrefixes[i] - currentItem;
michael@0 118 mDeltas.AppendElement(delta);
michael@0 119 numOfDeltas++;
michael@0 120 }
michael@0 121 currentItem = aPrefixes[i];
michael@0 122 }
michael@0 123
michael@0 124 mIndexPrefixes.Compact();
michael@0 125 mIndexStarts.Compact();
michael@0 126 mDeltas.Compact();
michael@0 127
michael@0 128 LOG(("Total number of indices: %d", mIndexPrefixes.Length()));
michael@0 129 LOG(("Total number of deltas: %d", mDeltas.Length()));
michael@0 130
michael@0 131 mHasPrefixes = true;
michael@0 132
michael@0 133 return NS_OK;
michael@0 134 }
michael@0 135
michael@0 136 NS_IMETHODIMP
michael@0 137 nsUrlClassifierPrefixSet::GetPrefixes(uint32_t* aCount,
michael@0 138 uint32_t** aPrefixes)
michael@0 139 {
michael@0 140 NS_ENSURE_ARG_POINTER(aCount);
michael@0 141 *aCount = 0;
michael@0 142 NS_ENSURE_ARG_POINTER(aPrefixes);
michael@0 143 *aPrefixes = nullptr;
michael@0 144
michael@0 145 nsTArray<uint32_t> aArray;
michael@0 146 uint32_t prefixLength = mIndexPrefixes.Length();
michael@0 147
michael@0 148 for (uint32_t i = 0; i < prefixLength; i++) {
michael@0 149 uint32_t prefix = mIndexPrefixes[i];
michael@0 150 uint32_t start = mIndexStarts[i];
michael@0 151 uint32_t end = (i == (prefixLength - 1)) ? mDeltas.Length()
michael@0 152 : mIndexStarts[i + 1];
michael@0 153 if (end > mDeltas.Length()) {
michael@0 154 return NS_ERROR_FILE_CORRUPTED;
michael@0 155 }
michael@0 156
michael@0 157 aArray.AppendElement(prefix);
michael@0 158 for (uint32_t j = start; j < end; j++) {
michael@0 159 prefix += mDeltas[j];
michael@0 160 aArray.AppendElement(prefix);
michael@0 161 }
michael@0 162 }
michael@0 163
michael@0 164 NS_ASSERTION(mIndexStarts.Length() + mDeltas.Length() == aArray.Length(),
michael@0 165 "Lengths are inconsistent");
michael@0 166
michael@0 167 uint32_t itemCount = aArray.Length();
michael@0 168
michael@0 169 uint32_t* retval = static_cast<uint32_t*>(nsMemory::Alloc(itemCount * sizeof(uint32_t)));
michael@0 170 NS_ENSURE_TRUE(retval, NS_ERROR_OUT_OF_MEMORY);
michael@0 171 for (uint32_t i = 0; i < itemCount; i++) {
michael@0 172 retval[i] = aArray[i];
michael@0 173 }
michael@0 174
michael@0 175 *aCount = itemCount;
michael@0 176 *aPrefixes = retval;
michael@0 177
michael@0 178 return NS_OK;
michael@0 179 }
michael@0 180
michael@0 181 uint32_t nsUrlClassifierPrefixSet::BinSearch(uint32_t start,
michael@0 182 uint32_t end,
michael@0 183 uint32_t target)
michael@0 184 {
michael@0 185 while (start != end && end >= start) {
michael@0 186 uint32_t i = start + ((end - start) >> 1);
michael@0 187 uint32_t value = mIndexPrefixes[i];
michael@0 188 if (value < target) {
michael@0 189 start = i + 1;
michael@0 190 } else if (value > target) {
michael@0 191 end = i - 1;
michael@0 192 } else {
michael@0 193 return i;
michael@0 194 }
michael@0 195 }
michael@0 196 return end;
michael@0 197 }
michael@0 198
michael@0 199 NS_IMETHODIMP
michael@0 200 nsUrlClassifierPrefixSet::Contains(uint32_t aPrefix, bool* aFound)
michael@0 201 {
michael@0 202 *aFound = false;
michael@0 203
michael@0 204 if (!mHasPrefixes) {
michael@0 205 return NS_OK;
michael@0 206 }
michael@0 207
michael@0 208 uint32_t target = aPrefix;
michael@0 209
michael@0 210 // We want to do a "Price is Right" binary search, that is, we want to find
michael@0 211 // the index of the value either equal to the target or the closest value
michael@0 212 // that is less than the target.
michael@0 213 //
michael@0 214 if (target < mIndexPrefixes[0]) {
michael@0 215 return NS_OK;
michael@0 216 }
michael@0 217
michael@0 218 // |binsearch| does not necessarily return the correct index (when the
michael@0 219 // target is not found) but rather it returns an index at least one away
michael@0 220 // from the correct index.
michael@0 221 // Because of this, we need to check if the target lies before the beginning
michael@0 222 // of the indices.
michael@0 223
michael@0 224 uint32_t i = BinSearch(0, mIndexPrefixes.Length() - 1, target);
michael@0 225 if (mIndexPrefixes[i] > target && i > 0) {
michael@0 226 i--;
michael@0 227 }
michael@0 228
michael@0 229 // Now search through the deltas for the target.
michael@0 230 uint32_t diff = target - mIndexPrefixes[i];
michael@0 231 uint32_t deltaIndex = mIndexStarts[i];
michael@0 232 uint32_t deltaSize = mDeltas.Length();
michael@0 233 uint32_t end = (i + 1 < mIndexStarts.Length()) ? mIndexStarts[i+1]
michael@0 234 : deltaSize;
michael@0 235
michael@0 236 // Sanity check the read values
michael@0 237 if (end > deltaSize) {
michael@0 238 return NS_ERROR_FILE_CORRUPTED;
michael@0 239 }
michael@0 240
michael@0 241 while (diff > 0 && deltaIndex < end) {
michael@0 242 diff -= mDeltas[deltaIndex];
michael@0 243 deltaIndex++;
michael@0 244 }
michael@0 245
michael@0 246 if (diff == 0) {
michael@0 247 *aFound = true;
michael@0 248 }
michael@0 249
michael@0 250 return NS_OK;
michael@0 251 }
michael@0 252
michael@0 253 MOZ_DEFINE_MALLOC_SIZE_OF(UrlClassifierMallocSizeOf)
michael@0 254
michael@0 255 NS_IMETHODIMP
michael@0 256 nsUrlClassifierPrefixSet::CollectReports(nsIHandleReportCallback* aHandleReport,
michael@0 257 nsISupports* aData)
michael@0 258 {
michael@0 259 return aHandleReport->Callback(
michael@0 260 EmptyCString(), mMemoryReportPath, KIND_HEAP, UNITS_BYTES,
michael@0 261 SizeOfIncludingThis(UrlClassifierMallocSizeOf),
michael@0 262 NS_LITERAL_CSTRING("Memory used by the prefix set for a URL classifier."),
michael@0 263 aData);
michael@0 264 }
michael@0 265
michael@0 266 size_t
michael@0 267 nsUrlClassifierPrefixSet::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf)
michael@0 268 {
michael@0 269 size_t n = 0;
michael@0 270 n += aMallocSizeOf(this);
michael@0 271 n += mDeltas.SizeOfExcludingThis(aMallocSizeOf);
michael@0 272 n += mIndexPrefixes.SizeOfExcludingThis(aMallocSizeOf);
michael@0 273 n += mIndexStarts.SizeOfExcludingThis(aMallocSizeOf);
michael@0 274 return n;
michael@0 275 }
michael@0 276
michael@0 277 NS_IMETHODIMP
michael@0 278 nsUrlClassifierPrefixSet::IsEmpty(bool * aEmpty)
michael@0 279 {
michael@0 280 *aEmpty = !mHasPrefixes;
michael@0 281 return NS_OK;
michael@0 282 }
michael@0 283
michael@0 284 nsresult
michael@0 285 nsUrlClassifierPrefixSet::LoadFromFd(AutoFDClose& fileFd)
michael@0 286 {
michael@0 287 uint32_t magic;
michael@0 288 int32_t read;
michael@0 289
michael@0 290 read = PR_Read(fileFd, &magic, sizeof(uint32_t));
michael@0 291 NS_ENSURE_TRUE(read == sizeof(uint32_t), NS_ERROR_FAILURE);
michael@0 292
michael@0 293 if (magic == PREFIXSET_VERSION_MAGIC) {
michael@0 294 uint32_t indexSize;
michael@0 295 uint32_t deltaSize;
michael@0 296
michael@0 297 read = PR_Read(fileFd, &indexSize, sizeof(uint32_t));
michael@0 298 NS_ENSURE_TRUE(read == sizeof(uint32_t), NS_ERROR_FILE_CORRUPTED);
michael@0 299 read = PR_Read(fileFd, &deltaSize, sizeof(uint32_t));
michael@0 300 NS_ENSURE_TRUE(read == sizeof(uint32_t), NS_ERROR_FILE_CORRUPTED);
michael@0 301
michael@0 302 if (indexSize == 0) {
michael@0 303 LOG(("stored PrefixSet is empty!"));
michael@0 304 return NS_OK;
michael@0 305 }
michael@0 306
michael@0 307 if (deltaSize > (indexSize * DELTAS_LIMIT)) {
michael@0 308 return NS_ERROR_FILE_CORRUPTED;
michael@0 309 }
michael@0 310
michael@0 311 mIndexStarts.SetLength(indexSize);
michael@0 312 mIndexPrefixes.SetLength(indexSize);
michael@0 313 mDeltas.SetLength(deltaSize);
michael@0 314
michael@0 315 int32_t toRead = indexSize*sizeof(uint32_t);
michael@0 316 read = PR_Read(fileFd, mIndexPrefixes.Elements(), toRead);
michael@0 317 NS_ENSURE_TRUE(read == toRead, NS_ERROR_FILE_CORRUPTED);
michael@0 318 read = PR_Read(fileFd, mIndexStarts.Elements(), toRead);
michael@0 319 NS_ENSURE_TRUE(read == toRead, NS_ERROR_FILE_CORRUPTED);
michael@0 320 if (deltaSize > 0) {
michael@0 321 toRead = deltaSize*sizeof(uint16_t);
michael@0 322 read = PR_Read(fileFd, mDeltas.Elements(), toRead);
michael@0 323 NS_ENSURE_TRUE(read == toRead, NS_ERROR_FILE_CORRUPTED);
michael@0 324 }
michael@0 325
michael@0 326 mHasPrefixes = true;
michael@0 327 } else {
michael@0 328 LOG(("Version magic mismatch, not loading"));
michael@0 329 return NS_ERROR_FILE_CORRUPTED;
michael@0 330 }
michael@0 331
michael@0 332 LOG(("Loading PrefixSet successful"));
michael@0 333
michael@0 334 return NS_OK;
michael@0 335 }
michael@0 336
michael@0 337 NS_IMETHODIMP
michael@0 338 nsUrlClassifierPrefixSet::LoadFromFile(nsIFile* aFile)
michael@0 339 {
michael@0 340 Telemetry::AutoTimer<Telemetry::URLCLASSIFIER_PS_FILELOAD_TIME> timer;
michael@0 341
michael@0 342 nsresult rv;
michael@0 343 AutoFDClose fileFd;
michael@0 344 rv = aFile->OpenNSPRFileDesc(PR_RDONLY | nsIFile::OS_READAHEAD,
michael@0 345 0, &fileFd.rwget());
michael@0 346 NS_ENSURE_SUCCESS(rv, rv);
michael@0 347
michael@0 348 return LoadFromFd(fileFd);
michael@0 349 }
michael@0 350
michael@0 351 nsresult
michael@0 352 nsUrlClassifierPrefixSet::StoreToFd(AutoFDClose& fileFd)
michael@0 353 {
michael@0 354 {
michael@0 355 Telemetry::AutoTimer<Telemetry::URLCLASSIFIER_PS_FALLOCATE_TIME> timer;
michael@0 356 int64_t size = 4 * sizeof(uint32_t);
michael@0 357 size += 2 * mIndexStarts.Length() * sizeof(uint32_t);
michael@0 358 size += mDeltas.Length() * sizeof(uint16_t);
michael@0 359
michael@0 360 mozilla::fallocate(fileFd, size);
michael@0 361 }
michael@0 362
michael@0 363 int32_t written;
michael@0 364 int32_t writelen = sizeof(uint32_t);
michael@0 365 uint32_t magic = PREFIXSET_VERSION_MAGIC;
michael@0 366 written = PR_Write(fileFd, &magic, writelen);
michael@0 367 NS_ENSURE_TRUE(written == writelen, NS_ERROR_FAILURE);
michael@0 368
michael@0 369 uint32_t indexSize = mIndexStarts.Length();
michael@0 370 uint32_t deltaSize = mDeltas.Length();
michael@0 371 written = PR_Write(fileFd, &indexSize, writelen);
michael@0 372 NS_ENSURE_TRUE(written == writelen, NS_ERROR_FAILURE);
michael@0 373 written = PR_Write(fileFd, &deltaSize, writelen);
michael@0 374 NS_ENSURE_TRUE(written == writelen, NS_ERROR_FAILURE);
michael@0 375
michael@0 376 writelen = indexSize * sizeof(uint32_t);
michael@0 377 written = PR_Write(fileFd, mIndexPrefixes.Elements(), writelen);
michael@0 378 NS_ENSURE_TRUE(written == writelen, NS_ERROR_FAILURE);
michael@0 379 written = PR_Write(fileFd, mIndexStarts.Elements(), writelen);
michael@0 380 NS_ENSURE_TRUE(written == writelen, NS_ERROR_FAILURE);
michael@0 381 if (deltaSize > 0) {
michael@0 382 writelen = deltaSize * sizeof(uint16_t);
michael@0 383 written = PR_Write(fileFd, mDeltas.Elements(), writelen);
michael@0 384 NS_ENSURE_TRUE(written == writelen, NS_ERROR_FAILURE);
michael@0 385 }
michael@0 386
michael@0 387 LOG(("Saving PrefixSet successful\n"));
michael@0 388
michael@0 389 return NS_OK;
michael@0 390 }
michael@0 391
michael@0 392 NS_IMETHODIMP
michael@0 393 nsUrlClassifierPrefixSet::StoreToFile(nsIFile* aFile)
michael@0 394 {
michael@0 395 AutoFDClose fileFd;
michael@0 396 nsresult rv = aFile->OpenNSPRFileDesc(PR_RDWR | PR_TRUNCATE | PR_CREATE_FILE,
michael@0 397 0644, &fileFd.rwget());
michael@0 398 NS_ENSURE_SUCCESS(rv, rv);
michael@0 399
michael@0 400 return StoreToFd(fileFd);
michael@0 401 }

mercurial