netwerk/cache2/CacheFileInputStream.cpp

Wed, 31 Dec 2014 06:55:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:50 +0100
changeset 2
7e26c7da4463
permissions
-rw-r--r--

Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 #include "CacheLog.h"
michael@0 6 #include "CacheFileInputStream.h"
michael@0 7
michael@0 8 #include "CacheFile.h"
michael@0 9 #include "nsStreamUtils.h"
michael@0 10 #include "nsThreadUtils.h"
michael@0 11 #include <algorithm>
michael@0 12
michael@0 13 namespace mozilla {
michael@0 14 namespace net {
michael@0 15
michael@0 16 NS_IMPL_ADDREF(CacheFileInputStream)
michael@0 17 NS_IMETHODIMP_(MozExternalRefCountType)
michael@0 18 CacheFileInputStream::Release()
michael@0 19 {
michael@0 20 NS_PRECONDITION(0 != mRefCnt, "dup release");
michael@0 21 nsrefcnt count = --mRefCnt;
michael@0 22 NS_LOG_RELEASE(this, count, "CacheFileInputStream");
michael@0 23
michael@0 24 if (0 == count) {
michael@0 25 mRefCnt = 1;
michael@0 26 delete (this);
michael@0 27 return 0;
michael@0 28 }
michael@0 29
michael@0 30 if (count == 1) {
michael@0 31 mFile->RemoveInput(this);
michael@0 32 }
michael@0 33
michael@0 34 return count;
michael@0 35 }
michael@0 36
michael@0 37 NS_INTERFACE_MAP_BEGIN(CacheFileInputStream)
michael@0 38 NS_INTERFACE_MAP_ENTRY(nsIInputStream)
michael@0 39 NS_INTERFACE_MAP_ENTRY(nsIAsyncInputStream)
michael@0 40 NS_INTERFACE_MAP_ENTRY(nsISeekableStream)
michael@0 41 NS_INTERFACE_MAP_ENTRY(mozilla::net::CacheFileChunkListener)
michael@0 42 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIInputStream)
michael@0 43 NS_INTERFACE_MAP_END_THREADSAFE
michael@0 44
michael@0 45 CacheFileInputStream::CacheFileInputStream(CacheFile *aFile)
michael@0 46 : mFile(aFile)
michael@0 47 , mPos(0)
michael@0 48 , mClosed(false)
michael@0 49 , mStatus(NS_OK)
michael@0 50 , mWaitingForUpdate(false)
michael@0 51 , mListeningForChunk(-1)
michael@0 52 , mInReadSegments(false)
michael@0 53 , mCallbackFlags(0)
michael@0 54 {
michael@0 55 LOG(("CacheFileInputStream::CacheFileInputStream() [this=%p]", this));
michael@0 56 MOZ_COUNT_CTOR(CacheFileInputStream);
michael@0 57 }
michael@0 58
michael@0 59 CacheFileInputStream::~CacheFileInputStream()
michael@0 60 {
michael@0 61 LOG(("CacheFileInputStream::~CacheFileInputStream() [this=%p]", this));
michael@0 62 MOZ_COUNT_DTOR(CacheFileInputStream);
michael@0 63 }
michael@0 64
michael@0 65 // nsIInputStream
michael@0 66 NS_IMETHODIMP
michael@0 67 CacheFileInputStream::Close()
michael@0 68 {
michael@0 69 LOG(("CacheFileInputStream::Close() [this=%p]", this));
michael@0 70 return CloseWithStatus(NS_OK);
michael@0 71 }
michael@0 72
michael@0 73 NS_IMETHODIMP
michael@0 74 CacheFileInputStream::Available(uint64_t *_retval)
michael@0 75 {
michael@0 76 CacheFileAutoLock lock(mFile);
michael@0 77 MOZ_ASSERT(!mInReadSegments);
michael@0 78
michael@0 79 if (mClosed) {
michael@0 80 LOG(("CacheFileInputStream::Available() - Stream is closed. [this=%p, "
michael@0 81 "status=0x%08x]", this, mStatus));
michael@0 82 return NS_FAILED(mStatus) ? mStatus : NS_BASE_STREAM_CLOSED;
michael@0 83 }
michael@0 84
michael@0 85 EnsureCorrectChunk(false);
michael@0 86 if (NS_FAILED(mStatus))
michael@0 87 return mStatus;
michael@0 88
michael@0 89 *_retval = 0;
michael@0 90
michael@0 91 if (mChunk) {
michael@0 92 int64_t canRead;
michael@0 93 const char *buf;
michael@0 94 CanRead(&canRead, &buf);
michael@0 95
michael@0 96 if (canRead > 0)
michael@0 97 *_retval = canRead;
michael@0 98 else if (canRead == 0 && !mFile->mOutput)
michael@0 99 return NS_BASE_STREAM_CLOSED;
michael@0 100 }
michael@0 101
michael@0 102 LOG(("CacheFileInputStream::Available() [this=%p, retval=%lld]",
michael@0 103 this, *_retval));
michael@0 104
michael@0 105 return NS_OK;
michael@0 106 }
michael@0 107
michael@0 108 NS_IMETHODIMP
michael@0 109 CacheFileInputStream::Read(char *aBuf, uint32_t aCount, uint32_t *_retval)
michael@0 110 {
michael@0 111 CacheFileAutoLock lock(mFile);
michael@0 112 MOZ_ASSERT(!mInReadSegments);
michael@0 113
michael@0 114 LOG(("CacheFileInputStream::Read() [this=%p, count=%d]", this, aCount));
michael@0 115
michael@0 116 nsresult rv;
michael@0 117
michael@0 118 if (mClosed) {
michael@0 119 LOG(("CacheFileInputStream::Read() - Stream is closed. [this=%p, "
michael@0 120 "status=0x%08x]", this, mStatus));
michael@0 121
michael@0 122 if NS_FAILED(mStatus)
michael@0 123 return mStatus;
michael@0 124
michael@0 125 *_retval = 0;
michael@0 126 return NS_OK;
michael@0 127 }
michael@0 128
michael@0 129 EnsureCorrectChunk(false);
michael@0 130 if (NS_FAILED(mStatus))
michael@0 131 return mStatus;
michael@0 132
michael@0 133 if (!mChunk) {
michael@0 134 if (mListeningForChunk == -1) {
michael@0 135 LOG((" no chunk, returning 0 read and NS_OK"));
michael@0 136 *_retval = 0;
michael@0 137 return NS_OK;
michael@0 138 }
michael@0 139 else {
michael@0 140 LOG((" waiting for chuck, returning WOULD_BLOCK"));
michael@0 141 return NS_BASE_STREAM_WOULD_BLOCK;
michael@0 142 }
michael@0 143 }
michael@0 144
michael@0 145 int64_t canRead;
michael@0 146 const char *buf;
michael@0 147 CanRead(&canRead, &buf);
michael@0 148
michael@0 149 if (canRead < 0) {
michael@0 150 // file was truncated ???
michael@0 151 MOZ_ASSERT(false, "SetEOF is currenty not implemented?!");
michael@0 152 *_retval = 0;
michael@0 153 rv = NS_OK;
michael@0 154 }
michael@0 155 else if (canRead > 0) {
michael@0 156 *_retval = std::min(static_cast<uint32_t>(canRead), aCount);
michael@0 157 memcpy(aBuf, buf, *_retval);
michael@0 158 mPos += *_retval;
michael@0 159
michael@0 160 EnsureCorrectChunk(!(canRead < aCount && mPos % kChunkSize == 0));
michael@0 161
michael@0 162 rv = NS_OK;
michael@0 163 }
michael@0 164 else {
michael@0 165 if (mFile->mOutput)
michael@0 166 rv = NS_BASE_STREAM_WOULD_BLOCK;
michael@0 167 else {
michael@0 168 *_retval = 0;
michael@0 169 rv = NS_OK;
michael@0 170 }
michael@0 171 }
michael@0 172
michael@0 173 LOG(("CacheFileInputStream::Read() [this=%p, rv=0x%08x, retval=%d",
michael@0 174 this, rv, *_retval));
michael@0 175
michael@0 176 return rv;
michael@0 177 }
michael@0 178
michael@0 179 NS_IMETHODIMP
michael@0 180 CacheFileInputStream::ReadSegments(nsWriteSegmentFun aWriter, void *aClosure,
michael@0 181 uint32_t aCount, uint32_t *_retval)
michael@0 182 {
michael@0 183 CacheFileAutoLock lock(mFile);
michael@0 184 MOZ_ASSERT(!mInReadSegments);
michael@0 185
michael@0 186 LOG(("CacheFileInputStream::ReadSegments() [this=%p, count=%d]",
michael@0 187 this, aCount));
michael@0 188
michael@0 189 nsresult rv;
michael@0 190
michael@0 191 if (mClosed) {
michael@0 192 LOG(("CacheFileInputStream::ReadSegments() - Stream is closed. [this=%p, "
michael@0 193 "status=0x%08x]", this, mStatus));
michael@0 194
michael@0 195 if NS_FAILED(mStatus)
michael@0 196 return mStatus;
michael@0 197
michael@0 198 *_retval = 0;
michael@0 199 return NS_OK;
michael@0 200 }
michael@0 201
michael@0 202 EnsureCorrectChunk(false);
michael@0 203 if (NS_FAILED(mStatus))
michael@0 204 return mStatus;
michael@0 205
michael@0 206 if (!mChunk) {
michael@0 207 if (mListeningForChunk == -1) {
michael@0 208 *_retval = 0;
michael@0 209 return NS_OK;
michael@0 210 }
michael@0 211 else {
michael@0 212 return NS_BASE_STREAM_WOULD_BLOCK;
michael@0 213 }
michael@0 214 }
michael@0 215
michael@0 216 int64_t canRead;
michael@0 217 const char *buf;
michael@0 218 CanRead(&canRead, &buf);
michael@0 219
michael@0 220 if (canRead < 0) {
michael@0 221 // file was truncated ???
michael@0 222 MOZ_ASSERT(false, "SetEOF is currenty not implemented?!");
michael@0 223 *_retval = 0;
michael@0 224 rv = NS_OK;
michael@0 225 }
michael@0 226 else if (canRead > 0) {
michael@0 227 uint32_t toRead = std::min(static_cast<uint32_t>(canRead), aCount);
michael@0 228
michael@0 229 // We need to release the lock to avoid lock re-entering
michael@0 230 #ifdef DEBUG
michael@0 231 int64_t oldPos = mPos;
michael@0 232 #endif
michael@0 233 mInReadSegments = true;
michael@0 234 lock.Unlock();
michael@0 235 rv = aWriter(this, aClosure, buf, 0, toRead, _retval);
michael@0 236 lock.Lock();
michael@0 237 mInReadSegments = false;
michael@0 238 #ifdef DEBUG
michael@0 239 MOZ_ASSERT(oldPos == mPos);
michael@0 240 #endif
michael@0 241
michael@0 242 if (NS_SUCCEEDED(rv)) {
michael@0 243 MOZ_ASSERT(*_retval <= toRead,
michael@0 244 "writer should not write more than we asked it to write");
michael@0 245 mPos += *_retval;
michael@0 246 }
michael@0 247
michael@0 248 EnsureCorrectChunk(!(canRead < aCount && mPos % kChunkSize == 0));
michael@0 249
michael@0 250 rv = NS_OK;
michael@0 251 }
michael@0 252 else {
michael@0 253 if (mFile->mOutput)
michael@0 254 rv = NS_BASE_STREAM_WOULD_BLOCK;
michael@0 255 else {
michael@0 256 *_retval = 0;
michael@0 257 rv = NS_OK;
michael@0 258 }
michael@0 259 }
michael@0 260
michael@0 261 LOG(("CacheFileInputStream::ReadSegments() [this=%p, rv=0x%08x, retval=%d",
michael@0 262 this, rv, *_retval));
michael@0 263
michael@0 264 return rv;
michael@0 265 }
michael@0 266
michael@0 267 NS_IMETHODIMP
michael@0 268 CacheFileInputStream::IsNonBlocking(bool *_retval)
michael@0 269 {
michael@0 270 *_retval = true;
michael@0 271 return NS_OK;
michael@0 272 }
michael@0 273
michael@0 274 // nsIAsyncInputStream
michael@0 275 NS_IMETHODIMP
michael@0 276 CacheFileInputStream::CloseWithStatus(nsresult aStatus)
michael@0 277 {
michael@0 278 CacheFileAutoLock lock(mFile);
michael@0 279 MOZ_ASSERT(!mInReadSegments);
michael@0 280
michael@0 281 LOG(("CacheFileInputStream::CloseWithStatus() [this=%p, aStatus=0x%08x]",
michael@0 282 this, aStatus));
michael@0 283
michael@0 284 if (mClosed) {
michael@0 285 MOZ_ASSERT(!mCallback);
michael@0 286 return NS_OK;
michael@0 287 }
michael@0 288
michael@0 289 mClosed = true;
michael@0 290 mStatus = NS_FAILED(aStatus) ? aStatus : NS_BASE_STREAM_CLOSED;
michael@0 291
michael@0 292 if (mChunk)
michael@0 293 ReleaseChunk();
michael@0 294
michael@0 295 // TODO propagate error from input stream to other streams ???
michael@0 296
michael@0 297 MaybeNotifyListener();
michael@0 298
michael@0 299 return NS_OK;
michael@0 300 }
michael@0 301
michael@0 302 NS_IMETHODIMP
michael@0 303 CacheFileInputStream::AsyncWait(nsIInputStreamCallback *aCallback,
michael@0 304 uint32_t aFlags,
michael@0 305 uint32_t aRequestedCount,
michael@0 306 nsIEventTarget *aEventTarget)
michael@0 307 {
michael@0 308 CacheFileAutoLock lock(mFile);
michael@0 309 MOZ_ASSERT(!mInReadSegments);
michael@0 310
michael@0 311 LOG(("CacheFileInputStream::AsyncWait() [this=%p, callback=%p, flags=%d, "
michael@0 312 "requestedCount=%d, eventTarget=%p]", this, aCallback, aFlags,
michael@0 313 aRequestedCount, aEventTarget));
michael@0 314
michael@0 315 mCallback = aCallback;
michael@0 316 mCallbackFlags = aFlags;
michael@0 317
michael@0 318 if (!mCallback) {
michael@0 319 if (mWaitingForUpdate) {
michael@0 320 mChunk->CancelWait(this);
michael@0 321 mWaitingForUpdate = false;
michael@0 322 }
michael@0 323 return NS_OK;
michael@0 324 }
michael@0 325
michael@0 326 if (mClosed) {
michael@0 327 NotifyListener();
michael@0 328 return NS_OK;
michael@0 329 }
michael@0 330
michael@0 331 EnsureCorrectChunk(false);
michael@0 332
michael@0 333 MaybeNotifyListener();
michael@0 334
michael@0 335 return NS_OK;
michael@0 336 }
michael@0 337
michael@0 338 // nsISeekableStream
michael@0 339 NS_IMETHODIMP
michael@0 340 CacheFileInputStream::Seek(int32_t whence, int64_t offset)
michael@0 341 {
michael@0 342 CacheFileAutoLock lock(mFile);
michael@0 343 MOZ_ASSERT(!mInReadSegments);
michael@0 344
michael@0 345 LOG(("CacheFileInputStream::Seek() [this=%p, whence=%d, offset=%lld]",
michael@0 346 this, whence, offset));
michael@0 347
michael@0 348 if (mClosed) {
michael@0 349 LOG(("CacheFileInputStream::Seek() - Stream is closed. [this=%p]", this));
michael@0 350 return NS_BASE_STREAM_CLOSED;
michael@0 351 }
michael@0 352
michael@0 353 int64_t newPos = offset;
michael@0 354 switch (whence) {
michael@0 355 case NS_SEEK_SET:
michael@0 356 break;
michael@0 357 case NS_SEEK_CUR:
michael@0 358 newPos += mPos;
michael@0 359 break;
michael@0 360 case NS_SEEK_END:
michael@0 361 newPos += mFile->mDataSize;
michael@0 362 break;
michael@0 363 default:
michael@0 364 NS_ERROR("invalid whence");
michael@0 365 return NS_ERROR_INVALID_ARG;
michael@0 366 }
michael@0 367 mPos = newPos;
michael@0 368 EnsureCorrectChunk(true);
michael@0 369
michael@0 370 LOG(("CacheFileInputStream::Seek() [this=%p, pos=%lld]", this, mPos));
michael@0 371 return NS_OK;
michael@0 372 }
michael@0 373
michael@0 374 NS_IMETHODIMP
michael@0 375 CacheFileInputStream::Tell(int64_t *_retval)
michael@0 376 {
michael@0 377 CacheFileAutoLock lock(mFile);
michael@0 378 MOZ_ASSERT(!mInReadSegments);
michael@0 379
michael@0 380 if (mClosed) {
michael@0 381 LOG(("CacheFileInputStream::Tell() - Stream is closed. [this=%p]", this));
michael@0 382 return NS_BASE_STREAM_CLOSED;
michael@0 383 }
michael@0 384
michael@0 385 *_retval = mPos;
michael@0 386
michael@0 387 LOG(("CacheFileInputStream::Tell() [this=%p, retval=%lld]", this, *_retval));
michael@0 388 return NS_OK;
michael@0 389 }
michael@0 390
michael@0 391 NS_IMETHODIMP
michael@0 392 CacheFileInputStream::SetEOF()
michael@0 393 {
michael@0 394 MOZ_ASSERT(false, "Don't call SetEOF on cache input stream");
michael@0 395 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 396 }
michael@0 397
michael@0 398 // CacheFileChunkListener
michael@0 399 nsresult
michael@0 400 CacheFileInputStream::OnChunkRead(nsresult aResult, CacheFileChunk *aChunk)
michael@0 401 {
michael@0 402 MOZ_CRASH("CacheFileInputStream::OnChunkRead should not be called!");
michael@0 403 return NS_ERROR_UNEXPECTED;
michael@0 404 }
michael@0 405
michael@0 406 nsresult
michael@0 407 CacheFileInputStream::OnChunkWritten(nsresult aResult, CacheFileChunk *aChunk)
michael@0 408 {
michael@0 409 MOZ_CRASH("CacheFileInputStream::OnChunkWritten should not be called!");
michael@0 410 return NS_ERROR_UNEXPECTED;
michael@0 411 }
michael@0 412
michael@0 413 nsresult
michael@0 414 CacheFileInputStream::OnChunkAvailable(nsresult aResult, uint32_t aChunkIdx,
michael@0 415 CacheFileChunk *aChunk)
michael@0 416 {
michael@0 417 CacheFileAutoLock lock(mFile);
michael@0 418 MOZ_ASSERT(!mInReadSegments);
michael@0 419
michael@0 420 LOG(("CacheFileInputStream::OnChunkAvailable() [this=%p, result=0x%08x, "
michael@0 421 "idx=%d, chunk=%p]", this, aResult, aChunkIdx, aChunk));
michael@0 422
michael@0 423 MOZ_ASSERT(mListeningForChunk != -1);
michael@0 424
michael@0 425 if (mListeningForChunk != static_cast<int64_t>(aChunkIdx)) {
michael@0 426 // This is not a chunk that we're waiting for
michael@0 427 LOG(("CacheFileInputStream::OnChunkAvailable() - Notification is for a "
michael@0 428 "different chunk. [this=%p, listeningForChunk=%lld]",
michael@0 429 this, mListeningForChunk));
michael@0 430
michael@0 431 return NS_OK;
michael@0 432 }
michael@0 433
michael@0 434 MOZ_ASSERT(!mChunk);
michael@0 435 MOZ_ASSERT(!mWaitingForUpdate);
michael@0 436 mListeningForChunk = -1;
michael@0 437
michael@0 438 if (mClosed) {
michael@0 439 MOZ_ASSERT(!mCallback);
michael@0 440
michael@0 441 LOG(("CacheFileInputStream::OnChunkAvailable() - Stream is closed, "
michael@0 442 "ignoring notification. [this=%p]", this));
michael@0 443
michael@0 444 return NS_OK;
michael@0 445 }
michael@0 446
michael@0 447 if (NS_SUCCEEDED(aResult)) {
michael@0 448 mChunk = aChunk;
michael@0 449 } else if (aResult != NS_ERROR_NOT_AVAILABLE) {
michael@0 450 // We store the error in mStatus, so we can propagate it later to consumer
michael@0 451 // in Read(), Available() etc. We need to handle NS_ERROR_NOT_AVAILABLE
michael@0 452 // differently since it is returned when the requested chunk is not
michael@0 453 // available and there is no writer that could create it, i.e. it means that
michael@0 454 // we've reached the end of the file.
michael@0 455 mStatus = aResult;
michael@0 456 }
michael@0 457
michael@0 458 MaybeNotifyListener();
michael@0 459
michael@0 460 return NS_OK;
michael@0 461 }
michael@0 462
michael@0 463 nsresult
michael@0 464 CacheFileInputStream::OnChunkUpdated(CacheFileChunk *aChunk)
michael@0 465 {
michael@0 466 CacheFileAutoLock lock(mFile);
michael@0 467 MOZ_ASSERT(!mInReadSegments);
michael@0 468
michael@0 469 LOG(("CacheFileInputStream::OnChunkUpdated() [this=%p, idx=%d]",
michael@0 470 this, aChunk->Index()));
michael@0 471
michael@0 472 if (!mWaitingForUpdate) {
michael@0 473 LOG(("CacheFileInputStream::OnChunkUpdated() - Ignoring notification since "
michael@0 474 "mWaitingforUpdate == false. [this=%p]", this));
michael@0 475
michael@0 476 return NS_OK;
michael@0 477 }
michael@0 478 else {
michael@0 479 mWaitingForUpdate = false;
michael@0 480 }
michael@0 481
michael@0 482 MOZ_ASSERT(mChunk == aChunk);
michael@0 483
michael@0 484 MaybeNotifyListener();
michael@0 485
michael@0 486 return NS_OK;
michael@0 487 }
michael@0 488
michael@0 489 void
michael@0 490 CacheFileInputStream::ReleaseChunk()
michael@0 491 {
michael@0 492 mFile->AssertOwnsLock();
michael@0 493
michael@0 494 LOG(("CacheFileInputStream::ReleaseChunk() [this=%p, idx=%d]",
michael@0 495 this, mChunk->Index()));
michael@0 496
michael@0 497 if (mWaitingForUpdate) {
michael@0 498 LOG(("CacheFileInputStream::ReleaseChunk() - Canceling waiting for update. "
michael@0 499 "[this=%p]", this));
michael@0 500
michael@0 501 mChunk->CancelWait(this);
michael@0 502 mWaitingForUpdate = false;
michael@0 503 }
michael@0 504
michael@0 505 mFile->ReleaseOutsideLock(mChunk.forget().take());
michael@0 506 }
michael@0 507
michael@0 508 void
michael@0 509 CacheFileInputStream::EnsureCorrectChunk(bool aReleaseOnly)
michael@0 510 {
michael@0 511 mFile->AssertOwnsLock();
michael@0 512
michael@0 513 LOG(("CacheFileInputStream::EnsureCorrectChunk() [this=%p, releaseOnly=%d]",
michael@0 514 this, aReleaseOnly));
michael@0 515
michael@0 516 nsresult rv;
michael@0 517
michael@0 518 uint32_t chunkIdx = mPos / kChunkSize;
michael@0 519
michael@0 520 if (mChunk) {
michael@0 521 if (mChunk->Index() == chunkIdx) {
michael@0 522 // we have a correct chunk
michael@0 523 LOG(("CacheFileInputStream::EnsureCorrectChunk() - Have correct chunk "
michael@0 524 "[this=%p, idx=%d]", this, chunkIdx));
michael@0 525
michael@0 526 return;
michael@0 527 }
michael@0 528 else {
michael@0 529 ReleaseChunk();
michael@0 530 }
michael@0 531 }
michael@0 532
michael@0 533 MOZ_ASSERT(!mWaitingForUpdate);
michael@0 534
michael@0 535 if (aReleaseOnly)
michael@0 536 return;
michael@0 537
michael@0 538 if (mListeningForChunk == static_cast<int64_t>(chunkIdx)) {
michael@0 539 // We're already waiting for this chunk
michael@0 540 LOG(("CacheFileInputStream::EnsureCorrectChunk() - Already listening for "
michael@0 541 "chunk %lld [this=%p]", mListeningForChunk, this));
michael@0 542
michael@0 543 return;
michael@0 544 }
michael@0 545
michael@0 546 rv = mFile->GetChunkLocked(chunkIdx, false, this, getter_AddRefs(mChunk));
michael@0 547 if (NS_FAILED(rv)) {
michael@0 548 LOG(("CacheFileInputStream::EnsureCorrectChunk() - GetChunkLocked failed. "
michael@0 549 "[this=%p, idx=%d, rv=0x%08x]", this, chunkIdx, rv));
michael@0 550 if (rv != NS_ERROR_NOT_AVAILABLE) {
michael@0 551 // We store the error in mStatus, so we can propagate it later to consumer
michael@0 552 // in Read(), Available() etc. We need to handle NS_ERROR_NOT_AVAILABLE
michael@0 553 // differently since it is returned when the requested chunk is not
michael@0 554 // available and there is no writer that could create it, i.e. it means
michael@0 555 // that we've reached the end of the file.
michael@0 556 mStatus = rv;
michael@0 557 }
michael@0 558 }
michael@0 559 else if (!mChunk) {
michael@0 560 mListeningForChunk = static_cast<int64_t>(chunkIdx);
michael@0 561 }
michael@0 562
michael@0 563 MaybeNotifyListener();
michael@0 564 }
michael@0 565
michael@0 566 void
michael@0 567 CacheFileInputStream::CanRead(int64_t *aCanRead, const char **aBuf)
michael@0 568 {
michael@0 569 mFile->AssertOwnsLock();
michael@0 570
michael@0 571 MOZ_ASSERT(mChunk);
michael@0 572 MOZ_ASSERT(mPos / kChunkSize == mChunk->Index());
michael@0 573
michael@0 574 uint32_t chunkOffset = mPos - (mPos / kChunkSize) * kChunkSize;
michael@0 575 *aCanRead = mChunk->DataSize() - chunkOffset;
michael@0 576 *aBuf = mChunk->BufForReading() + chunkOffset;
michael@0 577
michael@0 578 LOG(("CacheFileInputStream::CanRead() [this=%p, canRead=%lld]",
michael@0 579 this, *aCanRead));
michael@0 580 }
michael@0 581
michael@0 582 void
michael@0 583 CacheFileInputStream::NotifyListener()
michael@0 584 {
michael@0 585 mFile->AssertOwnsLock();
michael@0 586
michael@0 587 LOG(("CacheFileInputStream::NotifyListener() [this=%p]", this));
michael@0 588
michael@0 589 MOZ_ASSERT(mCallback);
michael@0 590
michael@0 591 if (!mCallbackTarget)
michael@0 592 mCallbackTarget = NS_GetCurrentThread();
michael@0 593
michael@0 594 nsCOMPtr<nsIInputStreamCallback> asyncCallback =
michael@0 595 NS_NewInputStreamReadyEvent(mCallback, mCallbackTarget);
michael@0 596
michael@0 597 mCallback = nullptr;
michael@0 598 mCallbackTarget = nullptr;
michael@0 599
michael@0 600 asyncCallback->OnInputStreamReady(this);
michael@0 601 }
michael@0 602
michael@0 603 void
michael@0 604 CacheFileInputStream::MaybeNotifyListener()
michael@0 605 {
michael@0 606 mFile->AssertOwnsLock();
michael@0 607
michael@0 608 LOG(("CacheFileInputStream::MaybeNotifyListener() [this=%p, mCallback=%p, "
michael@0 609 "mClosed=%d, mStatus=0x%08x, mChunk=%p, mListeningForChunk=%lld, "
michael@0 610 "mWaitingForUpdate=%d]", this, mCallback.get(), mClosed, mStatus,
michael@0 611 mChunk.get(), mListeningForChunk, mWaitingForUpdate));
michael@0 612
michael@0 613 if (!mCallback)
michael@0 614 return;
michael@0 615
michael@0 616 if (mClosed || NS_FAILED(mStatus)) {
michael@0 617 NotifyListener();
michael@0 618 return;
michael@0 619 }
michael@0 620
michael@0 621 if (!mChunk) {
michael@0 622 if (mListeningForChunk == -1) {
michael@0 623 // EOF, should we notify even if mCallbackFlags == WAIT_CLOSURE_ONLY ??
michael@0 624 NotifyListener();
michael@0 625 }
michael@0 626 return;
michael@0 627 }
michael@0 628
michael@0 629 MOZ_ASSERT(mPos / kChunkSize == mChunk->Index());
michael@0 630
michael@0 631 if (mWaitingForUpdate)
michael@0 632 return;
michael@0 633
michael@0 634 int64_t canRead;
michael@0 635 const char *buf;
michael@0 636 CanRead(&canRead, &buf);
michael@0 637
michael@0 638 if (canRead > 0) {
michael@0 639 if (!(mCallbackFlags & WAIT_CLOSURE_ONLY))
michael@0 640 NotifyListener();
michael@0 641 }
michael@0 642 else if (canRead == 0) {
michael@0 643 if (!mFile->mOutput) {
michael@0 644 // EOF
michael@0 645 NotifyListener();
michael@0 646 }
michael@0 647 else {
michael@0 648 mChunk->WaitForUpdate(this);
michael@0 649 mWaitingForUpdate = true;
michael@0 650 }
michael@0 651 }
michael@0 652 else {
michael@0 653 // Output have set EOF before mPos?
michael@0 654 MOZ_ASSERT(false, "SetEOF is currenty not implemented?!");
michael@0 655 NotifyListener();
michael@0 656 }
michael@0 657 }
michael@0 658
michael@0 659 // Memory reporting
michael@0 660
michael@0 661 size_t
michael@0 662 CacheFileInputStream::SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const
michael@0 663 {
michael@0 664 // Everything the stream keeps a reference to is already reported somewhere else.
michael@0 665 // mFile reports itself.
michael@0 666 // mChunk reported as part of CacheFile.
michael@0 667 // mCallback is usually CacheFile or a class that is reported elsewhere.
michael@0 668 return mallocSizeOf(this);
michael@0 669 }
michael@0 670
michael@0 671 } // net
michael@0 672 } // mozilla

mercurial