@@ -87,6 +87,8 @@ CacheEntry::Callback::Callback(CacheEntry* aEntry,
87
87
, mRecheckAfterWrite (false )
88
88
, mNotWanted (false )
89
89
, mSecret (aSecret)
90
+ , mDoomWhenFoundPinned (false )
91
+ , mDoomWhenFoundNonPinned (false )
90
92
{
91
93
MOZ_COUNT_CTOR (CacheEntry::Callback);
92
94
@@ -96,6 +98,22 @@ CacheEntry::Callback::Callback(CacheEntry* aEntry,
96
98
mEntry ->AddHandleRef ();
97
99
}
98
100
101
+ CacheEntry::Callback::Callback (CacheEntry* aEntry, bool aDoomWhenFoundInPinStatus)
102
+ : mEntry (aEntry)
103
+ , mReadOnly (false )
104
+ , mRevalidating (false )
105
+ , mCheckOnAnyThread (true )
106
+ , mRecheckAfterWrite (false )
107
+ , mNotWanted (false )
108
+ , mSecret (false )
109
+ , mDoomWhenFoundPinned (aDoomWhenFoundInPinStatus == true )
110
+ , mDoomWhenFoundNonPinned (aDoomWhenFoundInPinStatus == false )
111
+ {
112
+ MOZ_COUNT_CTOR (CacheEntry::Callback);
113
+ MOZ_ASSERT (mEntry ->HandlesCount ());
114
+ mEntry ->AddHandleRef ();
115
+ }
116
+
99
117
CacheEntry::Callback::Callback (CacheEntry::Callback const &aThat)
100
118
: mEntry (aThat.mEntry )
101
119
, mCallback (aThat.mCallback )
@@ -106,6 +124,8 @@ CacheEntry::Callback::Callback(CacheEntry::Callback const &aThat)
106
124
, mRecheckAfterWrite (aThat.mRecheckAfterWrite )
107
125
, mNotWanted (aThat.mNotWanted )
108
126
, mSecret (aThat.mSecret )
127
+ , mDoomWhenFoundPinned (aThat.mDoomWhenFoundPinned )
128
+ , mDoomWhenFoundNonPinned (aThat.mDoomWhenFoundNonPinned )
109
129
{
110
130
MOZ_COUNT_CTOR (CacheEntry::Callback);
111
131
@@ -136,6 +156,20 @@ void CacheEntry::Callback::ExchangeEntry(CacheEntry* aEntry)
136
156
mEntry = aEntry;
137
157
}
138
158
159
+ bool CacheEntry::Callback::DeferDoom (bool *aDoom) const
160
+ {
161
+ MOZ_ASSERT (mEntry ->mPinningKnown );
162
+
163
+ if (MOZ_UNLIKELY (mDoomWhenFoundNonPinned ) || MOZ_UNLIKELY (mDoomWhenFoundPinned )) {
164
+ *aDoom = (MOZ_UNLIKELY (mDoomWhenFoundNonPinned ) && MOZ_LIKELY (!mEntry ->mPinned )) ||
165
+ (MOZ_UNLIKELY (mDoomWhenFoundPinned ) && MOZ_UNLIKELY (mEntry ->mPinned ));
166
+
167
+ return true ;
168
+ }
169
+
170
+ return false ;
171
+ }
172
+
139
173
nsresult CacheEntry::Callback::OnCheckThread (bool *aOnCheckThread) const
140
174
{
141
175
if (!mCheckOnAnyThread ) {
@@ -164,7 +198,8 @@ CacheEntry::CacheEntry(const nsACString& aStorageID,
164
198
nsIURI* aURI,
165
199
const nsACString& aEnhanceID,
166
200
bool aUseDisk,
167
- bool aSkipSizeCheck)
201
+ bool aSkipSizeCheck,
202
+ bool aPin)
168
203
: mFrecency (0 )
169
204
, mSortingExpirationTime (uint32_t (-1 ))
170
205
, mLock (" CacheEntry" )
@@ -174,10 +209,12 @@ CacheEntry::CacheEntry(const nsACString& aStorageID,
174
209
, mStorageID (aStorageID)
175
210
, mUseDisk (aUseDisk)
176
211
, mSkipSizeCheck (aSkipSizeCheck)
177
- , mIsDoomed (false )
178
212
, mSecurityInfoLoaded (false )
179
213
, mPreventCallbacks (false )
180
214
, mHasData (false )
215
+ , mPinned (aPin)
216
+ , mPinningKnown (false )
217
+ , mIsDoomed (false )
181
218
, mState (NOTLOADED)
182
219
, mRegistration (NEVERREGISTERED)
183
220
, mWriter (nullptr )
@@ -350,16 +387,18 @@ bool CacheEntry::Load(bool aTruncate, bool aPriority)
350
387
if (NS_SUCCEEDED(CacheIndex::HasEntry (fileKey, &status))) {
351
388
switch (status) {
352
389
case CacheIndex::DOES_NOT_EXIST:
353
- LOG ((" entry doesn't exist according information from the index, truncating" ));
390
+ // Doesn't apply to memory-only entries, Load() is called only once for them
391
+ // and never again for their session lifetime.
354
392
if (!aTruncate && mUseDisk ) {
393
+ LOG ((" entry doesn't exist according information from the index, truncating" ));
355
394
reportMiss = true ;
395
+ aTruncate = true ;
356
396
}
357
- aTruncate = true ;
358
397
break ;
359
398
case CacheIndex::EXISTS:
360
399
case CacheIndex::DO_NOT_KNOW:
361
400
if (!mUseDisk ) {
362
- LOG ((" entry open as memory-only, but there is ( status=%d) a file , dooming it" , status));
401
+ LOG ((" entry open as memory-only, but there is a file, status=%d, dooming it" , status));
363
402
CacheFileIOManager::DoomFileByKey (fileKey, nullptr );
364
403
}
365
404
break ;
@@ -376,6 +415,7 @@ bool CacheEntry::Load(bool aTruncate, bool aPriority)
376
415
// mLoadStart will be used to calculate telemetry of life-time of this entry.
377
416
// Low resulution is then enough.
378
417
mLoadStart = TimeStamp::NowLoRes ();
418
+ mPinningKnown = true ;
379
419
} else {
380
420
mLoadStart = TimeStamp::Now ();
381
421
}
@@ -395,6 +435,7 @@ bool CacheEntry::Load(bool aTruncate, bool aPriority)
395
435
!mUseDisk ,
396
436
mSkipSizeCheck ,
397
437
aPriority,
438
+ mPinned ,
398
439
directLoad ? nullptr : this );
399
440
}
400
441
@@ -432,9 +473,10 @@ NS_IMETHODIMP CacheEntry::OnFileReady(nsresult aResult, bool aIsNew)
432
473
}
433
474
434
475
// OnFileReady, that is the only code that can transit from LOADING
435
- // to any follow-on state, can only be invoked ones on an entry,
436
- // thus no need to lock. Until this moment there is no consumer that
437
- // could manipulate the entry state.
476
+ // to any follow-on state and can only be invoked ones on an entry.
477
+ // Until this moment there is no consumer that could manipulate
478
+ // the entry state.
479
+
438
480
mozilla::MutexAutoLock lock (mLock );
439
481
440
482
MOZ_ASSERT (mState == LOADING);
@@ -445,6 +487,10 @@ NS_IMETHODIMP CacheEntry::OnFileReady(nsresult aResult, bool aIsNew)
445
487
446
488
mFileStatus = aResult;
447
489
490
+ mPinned = mFile ->IsPinned ();;
491
+ mPinningKnown = true ;
492
+ LOG ((" pinning=%d" , mPinned ));
493
+
448
494
if (mState == READY) {
449
495
mHasData = true ;
450
496
@@ -456,6 +502,7 @@ NS_IMETHODIMP CacheEntry::OnFileReady(nsresult aResult, bool aIsNew)
456
502
}
457
503
458
504
InvokeCallbacks ();
505
+
459
506
return NS_OK;
460
507
}
461
508
@@ -483,13 +530,21 @@ already_AddRefed<CacheEntryHandle> CacheEntry::ReopenTruncated(bool aMemoryOnly,
483
530
RefPtr<CacheEntryHandle> handle;
484
531
RefPtr<CacheEntry> newEntry;
485
532
{
533
+ if (mPinned ) {
534
+ MOZ_ASSERT (mUseDisk );
535
+ // We want to pin even no-store entries (the case we recreate a disk entry as
536
+ // a memory-only entry.)
537
+ aMemoryOnly = false ;
538
+ }
539
+
486
540
mozilla::MutexAutoUnlock unlock (mLock );
487
541
488
542
// The following call dooms this entry (calls DoomAlreadyRemoved on us)
489
543
nsresult rv = CacheStorageService::Self ()->AddStorageEntry (
490
544
GetStorageID (), GetURI (), GetEnhanceID (),
491
545
mUseDisk && !aMemoryOnly,
492
546
mSkipSizeCheck ,
547
+ mPinned ,
493
548
true , // always create
494
549
true , // truncate existing (this one)
495
550
getter_AddRefs (handle));
@@ -577,6 +632,8 @@ bool CacheEntry::InvokeCallbacks(bool aReadOnly)
577
632
{
578
633
mLock .AssertCurrentThreadOwns ();
579
634
635
+ RefPtr<CacheEntryHandle> recreatedHandle;
636
+
580
637
uint32_t i = 0 ;
581
638
while (i < mCallbacks .Length ()) {
582
639
if (mPreventCallbacks ) {
@@ -589,6 +646,18 @@ bool CacheEntry::InvokeCallbacks(bool aReadOnly)
589
646
return false ;
590
647
}
591
648
649
+ bool recreate;
650
+ if (mCallbacks [i].DeferDoom (&recreate)) {
651
+ mCallbacks .RemoveElementAt (i);
652
+ if (!recreate) {
653
+ continue ;
654
+ }
655
+
656
+ LOG ((" defer doom marker callback hit positive, recreating" ));
657
+ recreatedHandle = ReopenTruncated (!mUseDisk , nullptr );
658
+ break ;
659
+ }
660
+
592
661
if (mCallbacks [i].mReadOnly != aReadOnly) {
593
662
// Callback is not r/w or r/o, go to another one in line
594
663
++i;
@@ -625,6 +694,12 @@ bool CacheEntry::InvokeCallbacks(bool aReadOnly)
625
694
}
626
695
}
627
696
697
+ if (recreatedHandle) {
698
+ // Must be released outside of the lock, enters InvokeCallback on the new entry
699
+ mozilla::MutexAutoUnlock unlock (mLock );
700
+ recreatedHandle = nullptr ;
701
+ }
702
+
628
703
return true ;
629
704
}
630
705
@@ -991,6 +1066,13 @@ NS_IMETHODIMP CacheEntry::GetIsForcedValid(bool *aIsForcedValid)
991
1066
{
992
1067
NS_ENSURE_ARG (aIsForcedValid);
993
1068
1069
+ MOZ_ASSERT (mState > LOADING);
1070
+
1071
+ if (mPinned ) {
1072
+ *aIsForcedValid = true ;
1073
+ return NS_OK;
1074
+ }
1075
+
994
1076
nsAutoCString key;
995
1077
996
1078
nsresult rv = HashingKeyWithStorage (key);
@@ -1442,6 +1524,28 @@ void CacheEntry::SetRegistered(bool aRegistered)
1442
1524
}
1443
1525
}
1444
1526
1527
+ bool CacheEntry::DeferOrBypassRemovalOnPinStatus (bool aPinned)
1528
+ {
1529
+ LOG ((" CacheEntry::DeferOrBypassRemovalOnPinStatus [this=%p]" , this ));
1530
+
1531
+ mozilla::MutexAutoLock lock (mLock );
1532
+
1533
+ if (mPinningKnown ) {
1534
+ LOG ((" pinned=%d, caller=%d" , mPinned , aPinned));
1535
+ // Bypass when the pin status of this entry doesn't match the pin status
1536
+ // caller wants to remove
1537
+ return mPinned != aPinned;
1538
+ }
1539
+
1540
+ LOG ((" pinning unknown, caller=%d" , aPinned));
1541
+ // Oterwise, remember to doom after the status is determined for any
1542
+ // callback opening the entry after this point...
1543
+ Callback c (this , aPinned);
1544
+ RememberCallback (c);
1545
+ // ...and always bypass
1546
+ return true ;
1547
+ }
1548
+
1445
1549
bool CacheEntry::Purge (uint32_t aWhat)
1446
1550
{
1447
1551
LOG ((" CacheEntry::Purge [this=%p, what=%d]" , this , aWhat));
@@ -1523,6 +1627,10 @@ void CacheEntry::DoomAlreadyRemoved()
1523
1627
1524
1628
mIsDoomed = true ;
1525
1629
1630
+ // Pretend pinning is know. This entry is now doomed for good, so don't
1631
+ // bother with defering doom because of unknown pinning state any more.
1632
+ mPinningKnown = true ;
1633
+
1526
1634
// This schedules dooming of the file, dooming is ensured to happen
1527
1635
// sooner than demand to open the same file made after this point
1528
1636
// so that we don't get this file for any newer opened entry(s).
0 commit comments