Changeset 182856 in webkit
- Timestamp:
- Apr 15, 2015 12:54:21 PM (9 years ago)
- Location:
- trunk/Source/WebKit2
- Files:
-
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebKit2/ChangeLog
r182855 r182856 1 2015-04-15 Antti Koivisto <antti@apple.com> 2 3 Network Cache: Inline small body data to record file 4 https://bugs.webkit.org/show_bug.cgi?id=143783 5 6 Reviewed by Chris Dumez. 7 8 We currently save all body data as separate files. We can improve space efficiency and do less reads and writes 9 by inlining smaller resource bodies with the header. 10 11 * NetworkProcess/cache/NetworkCacheIOChannel.h: 12 * NetworkProcess/cache/NetworkCacheIOChannelCocoa.mm: 13 (WebKit::NetworkCache::IOChannel::read): 14 (WebKit::NetworkCache::IOChannel::readSync): 15 (WebKit::NetworkCache::IOChannel::write): 16 17 Add WorkQueue argument to allow specifying which queue the result is submitted to. 18 19 * NetworkProcess/cache/NetworkCacheStorage.cpp: 20 (WebKit::NetworkCache::decodeRecordMetaData): 21 22 Add a boolean indicating whether the body is inlined. 23 24 (WebKit::NetworkCache::decodeRecordHeader): 25 (WebKit::NetworkCache::Storage::decodeRecord): 26 (WebKit::NetworkCache::encodeRecordMetaData): 27 (WebKit::NetworkCache::Storage::storeBodyAsBlob): 28 (WebKit::NetworkCache::Storage::encodeRecord): 29 (WebKit::NetworkCache::Storage::dispatchReadOperation): 30 31 Read the record first, then read the blob if needed. 32 Submit the read operation directly from the main queue. Only thing we do is opening an IO channel 33 and that uses O_NONBLOCK. 34 Process the read results in the IO work queue where we now do the blob retrieval. 35 36 (WebKit::NetworkCache::shouldStoreBodyAsBlob): 37 38 The current threshold for saving a separate blob is 16KB. 39 40 (WebKit::NetworkCache::Storage::dispatchWriteOperation): 41 (WebKit::NetworkCache::Storage::traverse): 42 (WebKit::NetworkCache::createRecord): Deleted. 43 (WebKit::NetworkCache::encodeRecordHeader): Deleted. 44 * NetworkProcess/cache/NetworkCacheStorage.h: 45 1 46 2015-04-15 Tim Horton <timothy_horton@apple.com> 2 47 -
trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheIOChannel.h
r181700 r182856 32 32 #include <functional> 33 33 #include <wtf/ThreadSafeRefCounted.h> 34 #include <wtf/WorkQueue.h> 34 35 #include <wtf/text/WTFString.h> 35 36 … … 42 43 static Ref<IOChannel> open(const String& file, Type); 43 44 44 void read(size_t offset, size_t, std::function<void (Data&, int error)>); 45 void readSync(size_t offset, size_t, std::function<void (Data&, int error)>); 46 void write(size_t offset, const Data&, std::function<void (int error)>); 45 // Using nullptr as queue submits the result to the main queue. 46 // FIXME: We should add WorkQueue::main() instead. 47 void read(size_t offset, size_t, WorkQueue*, std::function<void (Data&, int error)>); 48 void readSync(size_t offset, size_t, WorkQueue*, std::function<void (Data&, int error)>); 49 void write(size_t offset, const Data&, WorkQueue*, std::function<void (int error)>); 47 50 48 51 const String& path() const { return m_path; } -
trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheIOChannelCocoa.mm
r182602 r182856 80 80 } 81 81 82 void IOChannel::read(size_t offset, size_t size, std::function<void (Data&, int error)> completionHandler)82 void IOChannel::read(size_t offset, size_t size, WorkQueue* queue, std::function<void (Data&, int error)> completionHandler) 83 83 { 84 84 RefPtr<IOChannel> channel(this); 85 85 bool didCallCompletionHandler = false; 86 dispatch_io_read(m_dispatchIO.get(), offset, size, dispatch_get_main_queue(), [channel, completionHandler, didCallCompletionHandler](bool done, dispatch_data_t fileData, int error) mutable { 86 auto dispatchQueue = queue ? queue->dispatchQueue() : dispatch_get_main_queue(); 87 dispatch_io_read(m_dispatchIO.get(), offset, size, dispatchQueue, [channel, completionHandler, didCallCompletionHandler](bool done, dispatch_data_t fileData, int error) mutable { 87 88 ASSERT_UNUSED(done, done || !didCallCompletionHandler); 88 89 if (didCallCompletionHandler) … … 96 97 97 98 // FIXME: It would be better to do without this. 98 void IOChannel::readSync(size_t offset, size_t size, std::function<void (Data&, int error)> completionHandler)99 void IOChannel::readSync(size_t offset, size_t size, WorkQueue* queue, std::function<void (Data&, int error)> completionHandler) 99 100 { 100 101 auto semaphore = adoptDispatch(dispatch_semaphore_create(0)); 101 read(offset, size, [semaphore, &completionHandler](Data& data, int error) {102 read(offset, size, queue, [semaphore, &completionHandler](Data& data, int error) { 102 103 completionHandler(data, error); 103 104 dispatch_semaphore_signal(semaphore.get()); … … 106 107 } 107 108 108 void IOChannel::write(size_t offset, const Data& data, std::function<void (int error)> completionHandler)109 void IOChannel::write(size_t offset, const Data& data, WorkQueue* queue, std::function<void (int error)> completionHandler) 109 110 { 110 111 RefPtr<IOChannel> channel(this); 111 112 auto dispatchData = data.dispatchData(); 112 dispatch_io_write(m_dispatchIO.get(), offset, dispatchData, dispatch_get_main_queue(), [channel, completionHandler](bool done, dispatch_data_t fileData, int error) { 113 auto dispatchQueue = queue ? queue->dispatchQueue() : dispatch_get_main_queue(); 114 dispatch_io_write(m_dispatchIO.get(), offset, dispatchData, dispatchQueue, [channel, completionHandler](bool done, dispatch_data_t fileData, int error) { 113 115 ASSERT_UNUSED(done, done); 114 116 completionHandler(error); -
trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheStorage.cpp
r182841 r182856 226 226 SHA1::Digest bodyHash; 227 227 uint64_t bodySize; 228 bool isBodyInline; 228 229 }; 229 230 … … 247 248 if (!decoder.decode(metaData.bodySize)) 248 249 return false; 250 if (!decoder.decode(metaData.isBodyInline)) 251 return false; 249 252 if (!decoder.verifyChecksum()) 250 253 return false; … … 256 259 } 257 260 258 static bool decodeRecordHeader(const Data& fileData, RecordMetaData& metaData, Data& data)261 static bool decodeRecordHeader(const Data& fileData, RecordMetaData& metaData, Data& headerData) 259 262 { 260 263 if (!decodeRecordMetaData(metaData, fileData)) { … … 268 271 } 269 272 270 autoheaderData = fileData.subrange(metaData.headerOffset, metaData.headerSize);273 headerData = fileData.subrange(metaData.headerOffset, metaData.headerSize); 271 274 if (metaData.headerChecksum != hashData(headerData)) { 272 275 LOG(NetworkCacheStorage, "(NetworkProcess) header checksum mismatch"); 273 276 return false; 274 277 } 275 data = { headerData };276 278 return true; 277 279 } 278 280 279 static std::unique_ptr<Storage::Record> createRecord(const Data& recordData, const BlobStorage::Blob& bodyBlob, const Key& key) 280 { 281 std::unique_ptr<Storage::Record> Storage::decodeRecord(const Data& recordData, const Key& key) 282 { 283 ASSERT(!RunLoop::isMain()); 284 281 285 RecordMetaData metaData; 282 286 Data headerData; … … 291 295 if (timeStamp > std::chrono::system_clock::now()) 292 296 return nullptr; 293 if (metaData.bodySize != bodyBlob.data.size()) 294 return nullptr; 295 if (metaData.bodyHash != bodyBlob.hash) 296 return nullptr; 297 298 Data bodyData; 299 if (metaData.isBodyInline) { 300 size_t bodyOffset = metaData.headerOffset + headerData.size(); 301 if (bodyOffset + metaData.bodySize != recordData.size()) 302 return nullptr; 303 bodyData = recordData.subrange(bodyOffset, metaData.bodySize); 304 if (metaData.bodyHash != computeSHA1(bodyData)) 305 return nullptr; 306 } else { 307 auto bodyPath = bodyPathForKey(key, recordsPath()); 308 auto bodyBlob = m_blobStorage.get(bodyPath); 309 if (metaData.bodySize != bodyBlob.data.size()) 310 return nullptr; 311 if (metaData.bodyHash != bodyBlob.hash) 312 return nullptr; 313 bodyData = bodyBlob.data; 314 } 297 315 298 316 return std::make_unique<Storage::Record>(Storage::Record { … … 300 318 timeStamp, 301 319 headerData, 302 body Blob.data320 bodyData 303 321 }); 304 322 } … … 315 333 encoder << metaData.bodyHash; 316 334 encoder << metaData.bodySize; 335 encoder << metaData.isBodyInline; 317 336 318 337 encoder.encodeChecksum(); … … 321 340 } 322 341 323 static Data encodeRecordHeader(const Storage::Record& record, SHA1::Digest bodyHash) 324 { 342 Optional<BlobStorage::Blob> Storage::storeBodyAsBlob(const Record& record, const MappedBodyHandler& mappedBodyHandler) 343 { 344 auto bodyPath = bodyPathForKey(record.key, recordsPath()); 345 346 // Store the body. 347 auto blob = m_blobStorage.add(bodyPath, record.body); 348 if (blob.data.isNull()) 349 return { }; 350 351 // Tell the client we now have a disk-backed map for this data. 352 if (mappedBodyHandler) { 353 RunLoop::main().dispatch([blob, mappedBodyHandler] { 354 mappedBodyHandler(blob.data); 355 }); 356 } 357 return blob; 358 } 359 360 Data Storage::encodeRecord(const Record& record, Optional<BlobStorage::Blob> blob) 361 { 362 ASSERT(!blob || bytesEqual(blob.value().data, record.body)); 363 325 364 RecordMetaData metaData(record.key); 326 365 metaData.epochRelativeTimeStamp = std::chrono::duration_cast<std::chrono::milliseconds>(record.timeStamp.time_since_epoch()); 327 366 metaData.headerChecksum = hashData(record.header); 328 367 metaData.headerSize = record.header.size(); 329 metaData.bodyHash = b odyHash;368 metaData.bodyHash = blob ? blob.value().hash : computeSHA1(record.body); 330 369 metaData.bodySize = record.body.size(); 370 metaData.isBodyInline = !blob; 331 371 332 372 auto encodedMetaData = encodeRecordMetaData(metaData); 333 373 auto headerData = concatenate(encodedMetaData, record.header); 374 375 if (metaData.isBodyInline) 376 return concatenate(headerData, record.body); 377 334 378 return { headerData }; 335 379 } … … 363 407 ASSERT(m_activeReadOperations.contains(&read)); 364 408 365 ioQueue().dispatch([this, &read] {366 auto recordsPath = this->recordsPath();367 auto recordPath = recordPathForKey(read.key, recordsPath); 368 auto bodyPath = bodyPathForKey(read.key, recordsPath);369 // FIXME: Body and header retrieves can be done in parallel.370 auto bodyBlob = m_blobStorage.get(bodyPath);371 372 RefPtr<IOChannel> channel = IOChannel::open(recordPath, IOChannel::Type::Read);373 channel->read(0, std::numeric_limits<size_t>::max(), [this, &read, bodyBlob](Data& fileData, int error){374 auto record = error ? nullptr : createRecord(fileData, bodyBlob, read.key);409 auto recordsPath = this->recordsPath(); 410 auto recordPath = recordPathForKey(read.key, recordsPath); 411 412 RefPtr<IOChannel> channel = IOChannel::open(recordPath, IOChannel::Type::Read); 413 channel->read(0, std::numeric_limits<size_t>::max(), &ioQueue(), [this, &read](const Data& fileData, int error) { 414 auto record = error ? nullptr : decodeRecord(fileData, read.key); 415 416 auto* recordPtr = record.release(); 417 RunLoop::main().dispatch([this, &read, recordPtr] { 418 auto record = std::unique_ptr<Record>(recordPtr); 375 419 finishReadOperation(read, WTF::move(record)); 376 420 }); … … 449 493 } 450 494 495 static bool shouldStoreBodyAsBlob(const Data& bodyData) 496 { 497 const size_t maximumInlineBodySize { 16 * 1024 }; 498 return bodyData.size() > maximumInlineBodySize; 499 } 500 451 501 void Storage::dispatchWriteOperation(const WriteOperation& write) 452 502 { … … 461 511 auto partitionPath = partitionPathForKey(write.record.key, recordsPath); 462 512 auto recordPath = recordPathForKey(write.record.key, recordsPath); 463 auto bodyPath = bodyPathForKey(write.record.key, recordsPath);464 513 465 514 WebCore::makeAllDirectories(partitionPath); 466 515 467 // Store the body. 468 auto blob = m_blobStorage.add(bodyPath, write.record.body); 469 if (blob.data.isNull()) { 470 RunLoop::main().dispatch([this, &write] { 471 finishWriteOperation(write); 472 }); 473 return; 474 } 475 476 // Tell the client we now have a disk-backed map for this data. 477 size_t minimumMapSize = pageSize(); 478 if (blob.data.size() >= minimumMapSize && blob.data.isMap() && write.mappedBodyHandler) { 479 auto& mappedBodyHandler = write.mappedBodyHandler; 480 RunLoop::main().dispatch([blob, mappedBodyHandler] { 481 mappedBodyHandler(blob.data); 482 }); 483 } 484 485 // Store the header and meta data. 486 auto encodedHeader = encodeRecordHeader(write.record, blob.hash); 516 bool shouldStoreAsBlob = shouldStoreBodyAsBlob(write.record.body); 517 auto bodyBlob = shouldStoreAsBlob ? storeBodyAsBlob(write.record, write.mappedBodyHandler) : Nullopt; 518 519 auto recordData = encodeRecord(write.record, bodyBlob); 520 487 521 auto channel = IOChannel::open(recordPath, IOChannel::Type::Create); 488 int fd = channel->fileDescriptor(); 489 size_t headerSize = encodedHeader.size(); 490 channel->write(0, encodedHeader, [this, &write, headerSize, fd](int error) { 522 size_t recordSize = recordData.size(); 523 channel->write(0, recordData, nullptr, [this, &write, recordSize](int error) { 491 524 // On error the entry still stays in the contents filter until next synchronization. 492 m_approximateSize += headerSize;525 m_approximateSize += recordSize; 493 526 finishWriteOperation(write); 494 527 … … 562 595 auto channel = IOChannel::open(recordPath, IOChannel::Type::Read); 563 596 // FIXME: Traversal is slower than it should be due to lack of parallelism. 564 channel->readSync(0, std::numeric_limits<size_t>::max(), [this, &traverseHandler, &info](Data& fileData, int) {597 channel->readSync(0, std::numeric_limits<size_t>::max(), nullptr, [this, &traverseHandler, &info](Data& fileData, int) { 565 598 RecordMetaData metaData; 566 599 Data headerData; -
trunk/Source/WebKit2/NetworkProcess/cache/NetworkCacheStorage.h
r182841 r182856 112 112 void finishWriteOperation(const WriteOperation&); 113 113 114 Optional<BlobStorage::Blob> storeBodyAsBlob(const Record&, const MappedBodyHandler&); 115 Data encodeRecord(const Record&, Optional<BlobStorage::Blob>); 116 std::unique_ptr<Record> decodeRecord(const Data&, const Key&); 117 114 118 void updateFileModificationTime(const String& path); 115 119
Note: See TracChangeset
for help on using the changeset viewer.