summaryrefslogtreecommitdiffstats
path: root/toolkit/components/places/History.h
blob: 03a31186fd8796587798bc5cc1b6ceec8adf6ca6 (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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
/* -*- 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_places_History_h_
#define mozilla_places_History_h_

#include <utility>

#include "Database.h"
#include "mozIAsyncHistory.h"
#include "mozIStorageConnection.h"
#include "mozilla/BaseHistory.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/Mutex.h"
#include "mozilla/dom/Link.h"
#include "mozilla/dom/PContentChild.h"
#include "nsTHashMap.h"
#include "nsIMemoryReporter.h"
#include "nsIObserver.h"
#include "nsString.h"
#include "nsTHashtable.h"
#include "nsTObserverArray.h"
#include "nsURIHashKey.h"

namespace mozilla::places {

struct VisitData;
class ConcurrentStatementsHolder;
class VisitedQuery;

// Initial size of mRecentlyVisitedURIs.
#define RECENTLY_VISITED_URIS_SIZE 64
// Microseconds after which a visit can be expired from mRecentlyVisitedURIs.
// When an URI is reloaded we only take into account the first visit to it, and
// ignore any subsequent visits, if they happen before this time has elapsed.
// A commonly found case is to reload a page every 5 minutes, so we pick a time
// larger than that.
#define RECENTLY_VISITED_URIS_MAX_AGE (6 * 60 * PR_USEC_PER_SEC)
// When notifying the main thread after inserting visits, we chunk the visits
// into medium-sized groups so that we can amortize the cost of the runnable
// without janking the main thread by expecting it to process hundreds at once.
#define NOTIFY_VISITS_CHUNK_SIZE 100

class History final : public BaseHistory,
                      public mozIAsyncHistory,
                      public nsIObserver,
                      public nsIMemoryReporter {
 public:
  NS_DECL_THREADSAFE_ISUPPORTS
  NS_DECL_MOZIASYNCHISTORY
  NS_DECL_NSIOBSERVER
  NS_DECL_NSIMEMORYREPORTER

  // IHistory
  NS_IMETHOD VisitURI(nsIWidget*, nsIURI*, nsIURI* aLastVisitedURI,
                      uint32_t aFlags, uint64_t aBrowserId) final;
  NS_IMETHOD SetURITitle(nsIURI*, const nsAString&) final;

  // BaseHistory
  void StartPendingVisitedQueries(PendingVisitedQueries&&) final;

  History();

  nsresult QueueVisitedStatement(RefPtr<VisitedQuery>);

  /**
   * Adds an entry in moz_places with the data in aVisitData.
   *
   * @param aPlace
   *        The visit data to use to populate a new row in moz_places.
   */
  nsresult InsertPlace(VisitData& aPlace);

  /**
   * Updates an entry in moz_places with the data in aVisitData.
   *
   * @param aPlace
   *        The visit data to use to update the existing row in moz_places.
   */
  nsresult UpdatePlace(const VisitData& aPlace);

  /**
   * Loads information about the page into _place from moz_places.
   *
   * @param _place
   *        The VisitData for the place we need to know information about.
   * @param [out] _exists
   *        Whether or the page was recorded in moz_places, false otherwise.
   */
  nsresult FetchPageInfo(VisitData& _place, bool* _exists);

  /**
   * Get the number of bytes of memory this History object is using,
   * including sizeof(*this))
   */
  size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf);

  /**
   * Obtains a pointer to this service.
   */
  static History* GetService();

  /**
   * Used by the service manager only.
   */
  static already_AddRefed<History> GetSingleton();

  template <int N>
  already_AddRefed<mozIStorageStatement> GetStatement(const char (&aQuery)[N]) {
    // May be invoked on both threads.
    const mozIStorageConnection* dbConn = GetConstDBConn();
    NS_ENSURE_TRUE(dbConn, nullptr);
    return mDB->GetStatement(aQuery);
  }

  already_AddRefed<mozIStorageStatement> GetStatement(
      const nsACString& aQuery) {
    // May be invoked on both threads.
    const mozIStorageConnection* dbConn = GetConstDBConn();
    NS_ENSURE_TRUE(dbConn, nullptr);
    return mDB->GetStatement(aQuery);
  }

  bool IsShuttingDown() {
    MutexAutoLock lockedScope(mShuttingDownMutex);
    return mShuttingDown;
  }

  /**
   * Helper function to append a new URI to mRecentlyVisitedURIs. See
   * mRecentlyVisitedURIs.
   * @param {nsIURI} aURI The URI to append
   * @param {bool} aHidden The hidden status of the visit being appended.
   */
  void AppendToRecentlyVisitedURIs(nsIURI* aURI, bool aHidden);

 private:
  virtual ~History();

  void InitMemoryReporter();

  /**
   * Obtains a read-write database connection, initializing the connection
   * if needed. Must be invoked on the main thread.
   */
  mozIStorageConnection* GetDBConn();

  /**
   * Obtains a read-write database connection, but won't try to initialize it.
   * May be invoked on both threads, but first one must invoke GetDBConn() on
   * the main-thread at least once.
   */
  const mozIStorageConnection* GetConstDBConn();

  /**
   * The database handle.  This is initialized lazily by the first call to
   * GetDBConn(), so never use it directly, or, if you really need, always
   * invoke GetDBConn() before.
   */
  RefPtr<mozilla::places::Database> mDB;

  RefPtr<ConcurrentStatementsHolder> mConcurrentStatementsHolder;

  /**
   * Remove any memory references to tasks and do not take on any more.
   */
  void Shutdown();

  static History* gService;

  // Ensures new tasks aren't started on destruction. Should only be changed on
  // the main thread.
  bool mShuttingDown;
  // This mutex guards mShuttingDown and should be acquired on the helper
  // thread.
  Mutex mShuttingDownMutex MOZ_UNANNOTATED;
  // Code running in the helper thread can acquire this mutex to block shutdown
  // from proceeding until done, otherwise it may be impossible to get
  // statements to execute and an insert operation could be interrupted in the
  // middle.
  Mutex mBlockShutdownMutex MOZ_UNANNOTATED;

  // Allow private access from the helper thread to acquire mutexes.
  friend class InsertVisitedURIs;

  /**
   * mRecentlyVisitedURIs remembers URIs which have been recently added to
   * history, to avoid saving these locations repeatedly in a short period.
   */
  struct RecentURIVisit {
    PRTime mTime;
    bool mHidden;
  };

  nsTHashMap<nsURIHashKey, RecentURIVisit> mRecentlyVisitedURIs;
};

}  // namespace mozilla::places

#endif  // mozilla_places_History_h_