Backout a74bd5095902, Bug 959405 - Please update the Buri Moz-central, 1.3, 1.2 with...
[gecko.git] / dom / quota / QuotaObject.cpp
blob947338d2e8e1cc6a1fb6da1bf9bc54a384922c03
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"
12 USING_QUOTA_NAMESPACE
14 void
15 QuotaObject::AddRef()
17 QuotaManager* quotaManager = QuotaManager::Get();
18 if (!quotaManager) {
19 NS_ERROR("Null quota manager, this shouldn't happen, possible leak!");
21 ++mRefCnt;
23 return;
26 MutexAutoLock lock(quotaManager->mQuotaMutex);
28 ++mRefCnt;
31 void
32 QuotaObject::Release()
34 QuotaManager* quotaManager = QuotaManager::Get();
35 if (!quotaManager) {
36 NS_ERROR("Null quota manager, this shouldn't happen, possible leak!");
38 nsrefcnt count = --mRefCnt;
39 if (count == 0) {
40 mRefCnt = 1;
41 delete this;
44 return;
48 MutexAutoLock lock(quotaManager->mQuotaMutex);
50 --mRefCnt;
52 if (mRefCnt > 0) {
53 return;
56 if (mOriginInfo) {
57 mOriginInfo->mQuotaObjects.Remove(mPath);
61 delete this;
64 void
65 QuotaObject::UpdateSize(int64_t aSize)
67 QuotaManager* quotaManager = QuotaManager::Get();
68 NS_ASSERTION(quotaManager, "Shouldn't be null!");
70 MutexAutoLock lock(quotaManager->mQuotaMutex);
72 if (!mOriginInfo) {
73 return;
76 GroupInfo* groupInfo = mOriginInfo->mGroupInfo;
78 if (groupInfo->IsForTemporaryStorage()) {
79 quotaManager->mTemporaryStorageUsage -= mSize;
81 groupInfo->mUsage -= mSize;
82 mOriginInfo->mUsage -= mSize;
84 mSize = aSize;
86 mOriginInfo->mUsage += mSize;
87 groupInfo->mUsage += mSize;
88 if (groupInfo->IsForTemporaryStorage()) {
89 quotaManager->mTemporaryStorageUsage += mSize;
93 bool
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) {
104 return true;
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
115 // finished.
116 if (!quotaManager->LockedQuotaIsLifted()) {
117 return false;
120 // Threads raced, the origin info removal has been done by some other
121 // thread.
122 if (!mOriginInfo) {
123 // The other thread could allocate more space.
124 if (end > mSize) {
125 mSize = end;
128 return true;
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,
139 group, origin);
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!");
145 mSize = end;
147 return true;
150 mOriginInfo->mUsage = newUsage;
152 groupInfo->mUsage = groupInfo->mUsage - mSize + end;
154 mSize = end;
156 return true;
159 NS_ASSERTION(groupInfo->mPersistenceType == PERSISTENCE_TYPE_TEMPORARY,
160 "Huh?");
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
172 // limit).
173 if (newGroupUsage > quotaManager->GetGroupLimit()) {
174 return false;
177 uint64_t newTemporaryStorageUsage = quotaManager->mTemporaryStorageUsage +
178 delta;
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) {
188 return false;
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);
201 // Relocked.
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,
214 group, origin);
216 #ifdef DEBUG
217 originInfos[i] = nullptr;
218 #endif
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.
226 delta = end - mSize;
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);
241 return false;
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
257 // than this one.
258 NS_ASSERTION(mSize < end, "This shouldn't happen!");
259 mSize = end;
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);
267 return true;
270 mOriginInfo->mUsage = newUsage;
271 groupInfo->mUsage = newGroupUsage;
272 quotaManager->mTemporaryStorageUsage = newTemporaryStorageUsage;
274 mSize = end;
276 return true;
279 void
280 OriginInfo::LockedDecreaseUsage(int64_t aSize)
282 AssertCurrentThreadOwnsQuotaMutex();
284 mUsage -= aSize;
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;
296 // static
297 PLDHashOperator
298 OriginInfo::ClearOriginInfoCallback(const nsAString& aKey,
299 QuotaObject* aValue,
300 void* aUserArg)
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();
324 return nullptr;
327 void
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;
346 void
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);
364 return;
369 void
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);
388 void
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);
409 nsRefPtr<GroupInfo>&
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:
419 default:
420 MOZ_CRASH("Bad persistence type value!");
421 return mPersistentStorageGroupInfo;