summaryrefslogtreecommitdiffstats
path: root/dom/cache/QuotaClientImpl.h
blob: 62001ce8d87c3c8e08d17197746b8f20e2bf9387 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef mozilla_dom_cache_QuotaClientImpl_h
#define mozilla_dom_cache_QuotaClientImpl_h

#include "mozilla/dom/QMResult.h"
#include "mozilla/dom/cache/QuotaClient.h"
#include "mozilla/dom/cache/FileUtils.h"
#include "mozilla/dom/quota/ResultExtensions.h"

namespace mozilla::dom::cache {

class CacheQuotaClient final : public quota::Client {
  static CacheQuotaClient* sInstance;

 public:
  using OriginMetadata = quota::OriginMetadata;
  using PersistenceType = quota::PersistenceType;
  using UsageInfo = quota::UsageInfo;

  CacheQuotaClient();

  static CacheQuotaClient* Get();

  virtual Type GetType() override;

  virtual Result<UsageInfo, nsresult> InitOrigin(
      PersistenceType aPersistenceType, const OriginMetadata& aOriginMetadata,
      const AtomicBool& aCanceled) override;

  virtual nsresult InitOriginWithoutTracking(
      PersistenceType aPersistenceType, const OriginMetadata& aOriginMetadata,
      const AtomicBool& aCanceled) override;

  virtual Result<UsageInfo, nsresult> GetUsageForOrigin(
      PersistenceType aPersistenceType, const OriginMetadata& aOriginMetadata,
      const AtomicBool& aCanceled) override;

  virtual void OnOriginClearCompleted(PersistenceType aPersistenceType,
                                      const nsACString& aOrigin) override;

  void OnRepositoryClearCompleted(PersistenceType aPersistenceType) override;

  virtual void ReleaseIOThreadObjects() override;

  void AbortOperationsForLocks(
      const DirectoryLockIdTable& aDirectoryLockIds) override;

  virtual void AbortOperationsForProcess(
      ContentParentId aContentParentId) override;

  virtual void AbortAllOperations() override;

  virtual void StartIdleMaintenance() override;

  virtual void StopIdleMaintenance() override;

  nsresult UpgradeStorageFrom2_0To2_1(nsIFile* aDirectory) override;

  template <typename Callable>
  nsresult MaybeUpdatePaddingFileInternal(nsIFile& aBaseDir,
                                          mozIStorageConnection& aConn,
                                          const int64_t aIncreaseSize,
                                          const int64_t aDecreaseSize,
                                          Callable&& aCommitHook) {
    MOZ_ASSERT(!NS_IsMainThread());
    MOZ_DIAGNOSTIC_ASSERT(aIncreaseSize >= 0);
    MOZ_DIAGNOSTIC_ASSERT(aDecreaseSize >= 0);

    // Temporary should be removed at the end of each action. If not, it means
    // the failure happened.
    const bool temporaryPaddingFileExist =
        DirectoryPaddingFileExists(aBaseDir, DirPaddingFile::TMP_FILE);

    if (aIncreaseSize == aDecreaseSize && !temporaryPaddingFileExist) {
      // Early return here, since most cache actions won't modify padding size.
      QM_TRY(MOZ_TO_RESULT(aCommitHook()));

      return NS_OK;
    }

    // Don't delete the temporary padding file in case of an error to force the
    // next action recalculate the padding size.
    QM_TRY(MOZ_TO_RESULT(
        UpdateDirectoryPaddingFile(aBaseDir, aConn, aIncreaseSize,
                                   aDecreaseSize, temporaryPaddingFileExist)));

    // Don't delete the temporary padding file in case of an error to force the
    // next action recalculate the padding size.
    QM_TRY(MOZ_TO_RESULT(aCommitHook()));

    QM_WARNONLY_TRY(MOZ_TO_RESULT(DirectoryPaddingFinalizeWrite(aBaseDir)),
                    ([&aBaseDir](const nsresult) {
                      // Force restore file next time.
                      QM_WARNONLY_TRY(QM_TO_RESULT(DirectoryPaddingDeleteFile(
                          aBaseDir, DirPaddingFile::FILE)));

                      // Ensure that we are able to force the padding file to
                      // be restored.
                      MOZ_ASSERT(DirectoryPaddingFileExists(
                          aBaseDir, DirPaddingFile::TMP_FILE));

                      // Since both the body file and header have been stored
                      // in the file-system, just make the action be resolve
                      // and let the padding file be restored in the next
                      // action.
                    }));

    return NS_OK;
  }

  nsresult RestorePaddingFileInternal(nsIFile* aBaseDir,
                                      mozIStorageConnection* aConn);

  nsresult WipePaddingFileInternal(
      const CacheDirectoryMetadata& aDirectoryMetadata, nsIFile* aBaseDir);

 private:
  ~CacheQuotaClient();

  void InitiateShutdown() override;
  bool IsShutdownCompleted() const override;
  nsCString GetShutdownStatus() const override;
  void ForceKillActors() override;
  void FinalizeShutdown() override;

  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CacheQuotaClient, override)
};

}  // namespace mozilla::dom::cache

#endif  // mozilla_dom_cache_QuotaClientImpl_h