1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "QuotaObject.h"
9 #include "QuotaManager.h"
10 #include "Utilities.h"
17 QuotaManager
* quotaManager
= QuotaManager::Get();
19 NS_ERROR("Null quota manager, this shouldn't happen, possible leak!");
26 MutexAutoLock
lock(quotaManager
->mQuotaMutex
);
32 QuotaObject::Release()
34 QuotaManager
* quotaManager
= QuotaManager::Get();
36 NS_ERROR("Null quota manager, this shouldn't happen, possible leak!");
38 nsrefcnt count
= --mRefCnt
;
48 MutexAutoLock
lock(quotaManager
->mQuotaMutex
);
57 mOriginInfo
->mQuotaObjects
.Remove(mPath
);
65 QuotaObject::UpdateSize(int64_t aSize
)
67 QuotaManager
* quotaManager
= QuotaManager::Get();
68 NS_ASSERTION(quotaManager
, "Shouldn't be null!");
70 MutexAutoLock
lock(quotaManager
->mQuotaMutex
);
76 GroupInfo
* groupInfo
= mOriginInfo
->mGroupInfo
;
78 if (groupInfo
->IsForTemporaryStorage()) {
79 quotaManager
->mTemporaryStorageUsage
-= mSize
;
81 groupInfo
->mUsage
-= mSize
;
82 mOriginInfo
->mUsage
-= mSize
;
86 mOriginInfo
->mUsage
+= mSize
;
87 groupInfo
->mUsage
+= mSize
;
88 if (groupInfo
->IsForTemporaryStorage()) {
89 quotaManager
->mTemporaryStorageUsage
+= mSize
;
94 QuotaObject::MaybeAllocateMoreSpace(int64_t aOffset
, int32_t aCount
)
96 int64_t end
= aOffset
+ aCount
;
98 QuotaManager
* quotaManager
= QuotaManager::Get();
99 NS_ASSERTION(quotaManager
, "Shouldn't be null!");
101 MutexAutoLock
lock(quotaManager
->mQuotaMutex
);
103 if (mSize
>= end
|| !mOriginInfo
) {
107 GroupInfo
* groupInfo
= mOriginInfo
->mGroupInfo
;
109 if (groupInfo
->IsForPersistentStorage()) {
110 uint64_t newUsage
= mOriginInfo
->mUsage
- mSize
+ end
;
112 if (newUsage
> mOriginInfo
->mLimit
) {
113 // This will block the thread, but it will also drop the mutex while
114 // waiting. The mutex will be reacquired again when the waiting is
116 if (!quotaManager
->LockedQuotaIsLifted()) {
120 // Threads raced, the origin info removal has been done by some other
123 // The other thread could allocate more space.
131 nsCString group
= mOriginInfo
->mGroupInfo
->mGroup
;
132 nsCString origin
= mOriginInfo
->mOrigin
;
134 mOriginInfo
->LockedClearOriginInfos();
135 NS_ASSERTION(!mOriginInfo
,
136 "Should have cleared in LockedClearOriginInfos!");
138 quotaManager
->LockedRemoveQuotaForOrigin(PERSISTENCE_TYPE_PERSISTENT
,
141 // Some other thread could increase the size without blocking (increasing
142 // the origin usage without hitting the limit), but no more than this one.
143 NS_ASSERTION(mSize
< end
, "This shouldn't happen!");
150 mOriginInfo
->mUsage
= newUsage
;
152 groupInfo
->mUsage
= groupInfo
->mUsage
- mSize
+ end
;
159 NS_ASSERTION(groupInfo
->mPersistenceType
== PERSISTENCE_TYPE_TEMPORARY
,
162 uint64_t delta
= end
- mSize
;
164 uint64_t newUsage
= mOriginInfo
->mUsage
+ delta
;
166 // Temporary storage has no limit for origin usage (there's a group and the
167 // global limit though).
169 uint64_t newGroupUsage
= groupInfo
->mUsage
+ delta
;
171 // Temporary storage has a hard limit for group usage (20 % of the global
173 if (newGroupUsage
> quotaManager
->GetGroupLimit()) {
177 uint64_t newTemporaryStorageUsage
= quotaManager
->mTemporaryStorageUsage
+
180 if (newTemporaryStorageUsage
> quotaManager
->mTemporaryStorageLimit
) {
181 // This will block the thread without holding the lock while waitting.
183 nsAutoTArray
<OriginInfo
*, 10> originInfos
;
184 uint64_t sizeToBeFreed
=
185 quotaManager
->LockedCollectOriginsForEviction(delta
, originInfos
);
187 if (!sizeToBeFreed
) {
191 NS_ASSERTION(sizeToBeFreed
>= delta
, "Huh?");
194 MutexAutoUnlock
autoUnlock(quotaManager
->mQuotaMutex
);
196 for (uint32_t i
= 0; i
< originInfos
.Length(); i
++) {
197 quotaManager
->DeleteTemporaryFilesForOrigin(originInfos
[i
]->mOrigin
);
203 NS_ASSERTION(mOriginInfo
, "How come?!");
205 nsTArray
<nsCString
> origins
;
206 for (uint32_t i
= 0; i
< originInfos
.Length(); i
++) {
207 OriginInfo
* originInfo
= originInfos
[i
];
209 NS_ASSERTION(originInfo
!= mOriginInfo
, "Deleted itself!");
211 nsCString group
= originInfo
->mGroupInfo
->mGroup
;
212 nsCString origin
= originInfo
->mOrigin
;
213 quotaManager
->LockedRemoveQuotaForOrigin(PERSISTENCE_TYPE_TEMPORARY
,
217 originInfos
[i
] = nullptr;
220 origins
.AppendElement(origin
);
223 // We unlocked and relocked several times so we need to recompute all the
224 // essential variables and recheck the group limit.
228 newUsage
= mOriginInfo
->mUsage
+ delta
;
230 newGroupUsage
= groupInfo
->mUsage
+ delta
;
232 if (newGroupUsage
> quotaManager
->GetGroupLimit()) {
233 // Unfortunately some other thread increased the group usage in the
234 // meantime and we are not below the group limit anymore.
236 // However, the origin eviction must be finalized in this case too.
237 MutexAutoUnlock
autoUnlock(quotaManager
->mQuotaMutex
);
239 quotaManager
->FinalizeOriginEviction(origins
);
244 newTemporaryStorageUsage
= quotaManager
->mTemporaryStorageUsage
+ delta
;
246 NS_ASSERTION(newTemporaryStorageUsage
<=
247 quotaManager
->mTemporaryStorageLimit
, "How come?!");
249 // Ok, we successfully freed enough space and the operation can continue
250 // without throwing the quota error.
252 mOriginInfo
->mUsage
= newUsage
;
253 groupInfo
->mUsage
= newGroupUsage
;
254 quotaManager
->mTemporaryStorageUsage
= newTemporaryStorageUsage
;;
256 // Some other thread could increase the size in the meantime, but no more
258 NS_ASSERTION(mSize
< end
, "This shouldn't happen!");
261 // Finally, release IO thread only objects and allow next synchronized
262 // ops for the evicted origins.
263 MutexAutoUnlock
autoUnlock(quotaManager
->mQuotaMutex
);
265 quotaManager
->FinalizeOriginEviction(origins
);
270 mOriginInfo
->mUsage
= newUsage
;
271 groupInfo
->mUsage
= newGroupUsage
;
272 quotaManager
->mTemporaryStorageUsage
= newTemporaryStorageUsage
;
280 OriginInfo::LockedDecreaseUsage(int64_t aSize
)
282 AssertCurrentThreadOwnsQuotaMutex();
286 mGroupInfo
->mUsage
-= aSize
;
288 if (mGroupInfo
->IsForTemporaryStorage()) {
289 QuotaManager
* quotaManager
= QuotaManager::Get();
290 NS_ASSERTION(quotaManager
, "Shouldn't be null!");
292 quotaManager
->mTemporaryStorageUsage
-= aSize
;
298 OriginInfo::ClearOriginInfoCallback(const nsAString
& aKey
,
302 NS_ASSERTION(!aKey
.IsEmpty(), "Empty key!");
303 NS_ASSERTION(aValue
, "Null pointer!");
305 aValue
->mOriginInfo
= nullptr;
307 return PL_DHASH_NEXT
;
310 already_AddRefed
<OriginInfo
>
311 GroupInfo::LockedGetOriginInfo(const nsACString
& aOrigin
)
313 AssertCurrentThreadOwnsQuotaMutex();
315 for (uint32_t index
= 0; index
< mOriginInfos
.Length(); index
++) {
316 nsRefPtr
<OriginInfo
>& originInfo
= mOriginInfos
[index
];
318 if (originInfo
->mOrigin
== aOrigin
) {
319 nsRefPtr
<OriginInfo
> result
= originInfo
;
320 return result
.forget();
328 GroupInfo::LockedAddOriginInfo(OriginInfo
* aOriginInfo
)
330 AssertCurrentThreadOwnsQuotaMutex();
332 NS_ASSERTION(!mOriginInfos
.Contains(aOriginInfo
),
333 "Replacing an existing entry!");
334 mOriginInfos
.AppendElement(aOriginInfo
);
336 mUsage
+= aOriginInfo
->mUsage
;
338 if (IsForTemporaryStorage()) {
339 QuotaManager
* quotaManager
= QuotaManager::Get();
340 NS_ASSERTION(quotaManager
, "Shouldn't be null!");
342 quotaManager
->mTemporaryStorageUsage
+= aOriginInfo
->mUsage
;
347 GroupInfo::LockedRemoveOriginInfo(const nsACString
& aOrigin
)
349 AssertCurrentThreadOwnsQuotaMutex();
351 for (uint32_t index
= 0; index
< mOriginInfos
.Length(); index
++) {
352 if (mOriginInfos
[index
]->mOrigin
== aOrigin
) {
353 mUsage
-= mOriginInfos
[index
]->mUsage
;
355 if (IsForTemporaryStorage()) {
356 QuotaManager
* quotaManager
= QuotaManager::Get();
357 NS_ASSERTION(quotaManager
, "Shouldn't be null!");
359 quotaManager
->mTemporaryStorageUsage
-= mOriginInfos
[index
]->mUsage
;
362 mOriginInfos
.RemoveElementAt(index
);
370 GroupInfo::LockedRemoveOriginInfos()
372 AssertCurrentThreadOwnsQuotaMutex();
374 for (uint32_t index
= mOriginInfos
.Length(); index
> 0; index
--) {
375 mUsage
-= mOriginInfos
[index
- 1]->mUsage
;
377 if (IsForTemporaryStorage()) {
378 QuotaManager
* quotaManager
= QuotaManager::Get();
379 NS_ASSERTION(quotaManager
, "Shouldn't be null!");
381 quotaManager
->mTemporaryStorageUsage
-= mOriginInfos
[index
- 1]->mUsage
;
384 mOriginInfos
.RemoveElementAt(index
- 1);
389 GroupInfo::LockedRemoveOriginInfosForPattern(const nsACString
& aPattern
)
391 AssertCurrentThreadOwnsQuotaMutex();
393 for (uint32_t index
= mOriginInfos
.Length(); index
> 0; index
--) {
394 if (PatternMatchesOrigin(aPattern
, mOriginInfos
[index
- 1]->mOrigin
)) {
395 mUsage
-= mOriginInfos
[index
- 1]->mUsage
;
397 if (IsForTemporaryStorage()) {
398 QuotaManager
* quotaManager
= QuotaManager::Get();
399 NS_ASSERTION(quotaManager
, "Shouldn't be null!");
401 quotaManager
->mTemporaryStorageUsage
-= mOriginInfos
[index
- 1]->mUsage
;
404 mOriginInfos
.RemoveElementAt(index
- 1);
410 GroupInfoPair::GetGroupInfoForPersistenceType(PersistenceType aPersistenceType
)
412 switch (aPersistenceType
) {
413 case PERSISTENCE_TYPE_PERSISTENT
:
414 return mPersistentStorageGroupInfo
;
415 case PERSISTENCE_TYPE_TEMPORARY
:
416 return mTemporaryStorageGroupInfo
;
418 case PERSISTENCE_TYPE_INVALID
:
420 MOZ_CRASH("Bad persistence type value!");
421 return mPersistentStorageGroupInfo
;