1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=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
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #ifndef mozilla_dom_cache_QuotaClientImpl_h
8 #define mozilla_dom_cache_QuotaClientImpl_h
9 
10 #include "mozilla/dom/cache/QuotaClient.h"
11 #include "mozilla/dom/cache/FileUtils.h"
12 
13 namespace mozilla {
14 namespace dom {
15 namespace cache {
16 
17 class CacheQuotaClient final : public quota::Client {
18   static CacheQuotaClient* sInstance;
19 
20  public:
21   using PersistenceType = quota::PersistenceType;
22   using UsageInfo = quota::UsageInfo;
23 
24   CacheQuotaClient();
25 
26   static CacheQuotaClient* Get();
27 
28   virtual Type GetType() override;
29   virtual nsresult InitOrigin(PersistenceType aPersistenceType,
30                               const nsACString& aGroup,
31                               const nsACString& aOrigin,
32                               const AtomicBool& aCanceled,
33                               UsageInfo* aUsageInfo) override;
34 
35   virtual nsresult GetUsageForOrigin(PersistenceType aPersistenceType,
36                                      const nsACString& aGroup,
37                                      const nsACString& aOrigin,
38                                      const AtomicBool& aCanceled,
39                                      UsageInfo* aUsageInfo) override;
40 
41   virtual void OnOriginClearCompleted(PersistenceType aPersistenceType,
42                                       const nsACString& aOrigin) override;
43 
44   virtual void ReleaseIOThreadObjects() override;
45 
46   virtual void AbortOperations(const nsACString& aOrigin) override;
47 
48   virtual void AbortOperationsForProcess(
49       ContentParentId aContentParentId) override;
50 
51   virtual void StartIdleMaintenance() override;
52 
53   virtual void StopIdleMaintenance() override;
54 
55   virtual void ShutdownWorkThreads() override;
56 
57   nsresult UpgradeStorageFrom2_0To2_1(nsIFile* aDirectory) override;
58 
59   template <typename Callable>
MaybeUpdatePaddingFileInternal(nsIFile * aBaseDir,mozIStorageConnection * aConn,const int64_t aIncreaseSize,const int64_t aDecreaseSize,Callable aCommitHook)60   nsresult MaybeUpdatePaddingFileInternal(nsIFile* aBaseDir,
61                                           mozIStorageConnection* aConn,
62                                           const int64_t aIncreaseSize,
63                                           const int64_t aDecreaseSize,
64                                           Callable aCommitHook) {
65     MOZ_ASSERT(!NS_IsMainThread());
66     MOZ_DIAGNOSTIC_ASSERT(aBaseDir);
67     MOZ_DIAGNOSTIC_ASSERT(aConn);
68     MOZ_DIAGNOSTIC_ASSERT(aIncreaseSize >= 0);
69     MOZ_DIAGNOSTIC_ASSERT(aDecreaseSize >= 0);
70 
71     nsresult rv;
72 
73     // Temporary should be removed at the end of each action. If not, it means
74     // the failure happened.
75     bool temporaryPaddingFileExist =
76         mozilla::dom::cache::DirectoryPaddingFileExists(
77             aBaseDir, DirPaddingFile::TMP_FILE);
78 
79     if (aIncreaseSize == aDecreaseSize && !temporaryPaddingFileExist) {
80       // Early return here, since most cache actions won't modify padding size.
81       rv = aCommitHook();
82       Unused << NS_WARN_IF(NS_FAILED(rv));
83       return rv;
84     }
85 
86     {
87       MutexAutoLock lock(mDirPaddingFileMutex);
88       rv = mozilla::dom::cache::LockedUpdateDirectoryPaddingFile(
89           aBaseDir, aConn, aIncreaseSize, aDecreaseSize,
90           temporaryPaddingFileExist);
91       if (NS_WARN_IF(NS_FAILED(rv))) {
92         // Don't delete the temporary padding file here to force the next action
93         // recalculate the padding size.
94         return rv;
95       }
96 
97       rv = aCommitHook();
98       if (NS_WARN_IF(NS_FAILED(rv))) {
99         // Don't delete the temporary padding file here to force the next action
100         // recalculate the padding size.
101         return rv;
102       }
103 
104       rv = mozilla::dom::cache::LockedDirectoryPaddingFinalizeWrite(aBaseDir);
105       if (NS_WARN_IF(NS_FAILED(rv))) {
106         // Force restore file next time.
107         Unused << mozilla::dom::cache::LockedDirectoryPaddingDeleteFile(
108             aBaseDir, DirPaddingFile::FILE);
109 
110         // Ensure that we are able to force the padding file to be restored.
111         MOZ_ASSERT(mozilla::dom::cache::DirectoryPaddingFileExists(
112             aBaseDir, DirPaddingFile::TMP_FILE));
113 
114         // Since both the body file and header have been stored in the
115         // file-system, just make the action be resolve and let the padding file
116         // be restored in the next action.
117         rv = NS_OK;
118       }
119     }
120 
121     return rv;
122   }
123 
124   nsresult RestorePaddingFileInternal(nsIFile* aBaseDir,
125                                       mozIStorageConnection* aConn);
126 
127   nsresult WipePaddingFileInternal(const QuotaInfo& aQuotaInfo,
128                                    nsIFile* aBaseDir);
129 
130  private:
131   ~CacheQuotaClient();
132 
133   nsresult GetUsageForOriginInternal(PersistenceType aPersistenceType,
134                                      const nsACString& aGroup,
135                                      const nsACString& aOrigin,
136                                      const AtomicBool& aCanceled,
137                                      bool aInitializing, UsageInfo* aUsageInfo);
138 
139   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CacheQuotaClient, override)
140 
141   // Mutex lock to protect directroy padding files. It should only be acquired
142   // in DOM Cache IO threads and Quota IO thread.
143   mozilla::Mutex mDirPaddingFileMutex;
144 };
145 
146 }  // namespace cache
147 }  // namespace dom
148 }  // namespace mozilla
149 
150 #endif  // mozilla_dom_cache_QuotaClientImpl_h
151