Source code

Revision control

Other Tools

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_StorageDBThread_h
8
#define mozilla_dom_StorageDBThread_h
9
10
#include "prthread.h"
11
#include "prinrval.h"
12
#include "nsTArray.h"
13
#include "mozilla/Atomics.h"
14
#include "mozilla/Monitor.h"
15
#include "mozilla/BasePrincipal.h"
16
#include "mozilla/storage/StatementCache.h"
17
#include "mozilla/TimeStamp.h"
18
#include "nsAutoPtr.h"
19
#include "nsString.h"
20
#include "nsCOMPtr.h"
21
#include "nsClassHashtable.h"
22
#include "nsIFile.h"
23
#include "nsIThreadInternal.h"
24
25
class mozIStorageConnection;
26
27
namespace mozilla {
28
namespace dom {
29
30
class LocalStorageCacheBridge;
31
class StorageUsageBridge;
32
class StorageUsage;
33
34
typedef mozilla::storage::StatementCache<mozIStorageStatement> StatementCache;
35
36
// XXX Fix me!
37
// 1. Move comments to StorageDBThread/StorageDBChild.
38
// 2. Devirtualize relevant methods in StorageDBThread/StorageDBChild.
39
// 3. Remove relevant methods in StorageDBThread/StorageDBChild that are
40
// unused.
41
// 4. Remove this class completely.
42
//
43
// See bug 1387636 for more details.
44
#if 0
45
// Interface used by the cache to post operations to the asynchronous
46
// database thread or process.
47
class StorageDBBridge
48
{
49
public:
50
StorageDBBridge();
51
virtual ~StorageDBBridge() {}
52
53
// Ensures the database engine is started
54
virtual nsresult Init() = 0;
55
56
// Releases the database and disallows its usage
57
virtual nsresult Shutdown() = 0;
58
59
// Asynchronously fills the cache with data from the database for first use.
60
// When |aPriority| is true, the preload operation is scheduled as the first
61
// one. This method is responsible to keep hard reference to the cache for
62
// the time of the preload or, when preload cannot be performed, call
63
// LoadDone() immediately.
64
virtual void AsyncPreload(LocalStorageCacheBridge* aCache,
65
bool aPriority = false) = 0;
66
67
// Asynchronously fill the |usage| object with actual usage of data by its
68
// scope. The scope is eTLD+1 tops, never deeper subdomains.
69
virtual void AsyncGetUsage(StorageUsageBridge* aUsage) = 0;
70
71
// Synchronously fills the cache, when |aForceSync| is false and cache already
72
// got some data before, the method waits for the running preload to finish
73
virtual void SyncPreload(LocalStorageCacheBridge* aCache,
74
bool aForceSync = false) = 0;
75
76
// Called when an existing key is modified in the storage, schedules update to
77
// the database
78
virtual nsresult AsyncAddItem(LocalStorageCacheBridge* aCache,
79
const nsAString& aKey,
80
const nsAString& aValue) = 0;
81
82
// Called when an existing key is modified in the storage, schedules update to
83
// the database
84
virtual nsresult AsyncUpdateItem(LocalStorageCacheBridge* aCache,
85
const nsAString& aKey,
86
const nsAString& aValue) = 0;
87
88
// Called when an item is removed from the storage, schedules delete of the
89
// key
90
virtual nsresult AsyncRemoveItem(LocalStorageCacheBridge* aCache,
91
const nsAString& aKey) = 0;
92
93
// Called when the whole storage is cleared by the DOM API, schedules delete
94
// of the scope
95
virtual nsresult AsyncClear(LocalStorageCacheBridge* aCache) = 0;
96
97
// Called when chrome deletes e.g. cookies, schedules delete of the whole
98
// database
99
virtual void AsyncClearAll() = 0;
100
101
// Called when only a domain and its subdomains is about to clear
102
virtual void AsyncClearMatchingOrigin(const nsACString& aOriginNoSuffix) = 0;
103
104
// Called when data matching an origin pattern have to be cleared
105
virtual void AsyncClearMatchingOriginAttributes(const OriginAttributesPattern& aPattern) = 0;
106
107
// Forces scheduled DB operations to be early flushed to the disk
108
virtual void AsyncFlush() = 0;
109
110
// Check whether the scope has any data stored on disk and is thus allowed to
111
// preload
112
virtual bool ShouldPreloadOrigin(const nsACString& aOriginNoSuffix) = 0;
113
};
114
#endif
115
116
// The implementation of the the database engine, this directly works
117
// with the sqlite or any other db API we are based on
118
// This class is resposible for collecting and processing asynchronous
119
// DB operations over caches (LocalStorageCache) communicating though
120
// LocalStorageCacheBridge interface class
121
class StorageDBThread final {
122
public:
123
class PendingOperations;
124
125
// Representation of a singe database task, like adding and removing keys,
126
// (pre)loading the whole origin data, cleaning.
127
class DBOperation {
128
public:
129
typedef enum {
130
// Only operation that reads data from the database
131
opPreload,
132
// The same as opPreload, just executed with highest priority
133
opPreloadUrgent,
134
135
// Load usage of a scope
136
opGetUsage,
137
138
// Operations invoked by the DOM content API
139
opAddItem,
140
opUpdateItem,
141
opRemoveItem,
142
// Clears a specific single origin data
143
opClear,
144
145
// Operations invoked by chrome
146
147
// Clear all the data stored in the database, for all scopes, no
148
// exceptions
149
opClearAll,
150
// Clear data under a domain and all its subdomains regardless
151
// OriginAttributes value
152
opClearMatchingOrigin,
153
// Clear all data matching an OriginAttributesPattern regardless a domain
154
opClearMatchingOriginAttributes,
155
} OperationType;
156
157
explicit DBOperation(const OperationType aType,
158
LocalStorageCacheBridge* aCache = nullptr,
159
const nsAString& aKey = EmptyString(),
160
const nsAString& aValue = EmptyString());
161
DBOperation(const OperationType aType, StorageUsageBridge* aUsage);
162
DBOperation(const OperationType aType, const nsACString& aOriginNoSuffix);
163
DBOperation(const OperationType aType,
164
const OriginAttributesPattern& aOriginNoSuffix);
165
~DBOperation();
166
167
// Executes the operation, doesn't necessarity have to be called on the I/O
168
// thread
169
void PerformAndFinalize(StorageDBThread* aThread);
170
171
// Finalize the operation, i.e. do any internal cleanup and finish calls
172
void Finalize(nsresult aRv);
173
174
// The operation type
175
OperationType Type() const { return mType; }
176
177
// The origin in the database usage format (reversed)
178
const nsCString OriginNoSuffix() const;
179
180
// The origin attributes suffix
181
const nsCString OriginSuffix() const;
182
183
// |origin suffix + origin key| the operation is working with or a scope
184
// pattern to delete with simple SQL's "LIKE %" from the database.
185
const nsCString Origin() const;
186
187
// |origin suffix + origin key + key| the operation is working with
188
const nsCString Target() const;
189
190
// Pattern to delete matching data with this op
191
const OriginAttributesPattern& OriginPattern() const {
192
return mOriginPattern;
193
}
194
195
private:
196
// The operation implementation body
197
nsresult Perform(StorageDBThread* aThread);
198
199
friend class PendingOperations;
200
OperationType mType;
201
RefPtr<LocalStorageCacheBridge> mCache;
202
RefPtr<StorageUsageBridge> mUsage;
203
nsString const mKey;
204
nsString const mValue;
205
nsCString const mOrigin;
206
OriginAttributesPattern const mOriginPattern;
207
};
208
209
// Encapsulation of collective and coalescing logic for all pending operations
210
// except preloads that are handled separately as priority operations
211
class PendingOperations {
212
public:
213
PendingOperations();
214
215
// Method responsible for coalescing redundant update operations with the
216
// same |Target()| or clear operations with the same or matching |Origin()|
217
void Add(DBOperation* aOperation);
218
219
// True when there are some scheduled operations to flush on disk
220
bool HasTasks() const;
221
222
// Moves collected operations to a local flat list to allow execution of the
223
// operation list out of the thread lock
224
bool Prepare();
225
226
// Executes the previously |Prepared()'ed| list of operations, returns
227
// result, but doesn't handle it in any way in case of a failure
228
nsresult Execute(StorageDBThread* aThread);
229
230
// Finalizes the pending operation list, returns false when too many
231
// operations failed to flush what indicates a long standing issue with the
232
// database access.
233
bool Finalize(nsresult aRv);
234
235
// true when a clear that deletes the given origin attr pattern and/or
236
// origin key is among the pending operations; when a preload for that scope
237
// is being scheduled, it must be finished right away
238
bool IsOriginClearPending(const nsACString& aOriginSuffix,
239
const nsACString& aOriginNoSuffix) const;
240
241
// Checks whether there is a pending update operation for this scope.
242
bool IsOriginUpdatePending(const nsACString& aOriginSuffix,
243
const nsACString& aOriginNoSuffix) const;
244
245
private:
246
// Returns true iff new operation is of type newType and there is a pending
247
// operation of type pendingType for the same key (target).
248
bool CheckForCoalesceOpportunity(DBOperation* aNewOp,
249
DBOperation::OperationType aPendingType,
250
DBOperation::OperationType aNewType);
251
252
// List of all clearing operations, executed first
253
nsClassHashtable<nsCStringHashKey, DBOperation> mClears;
254
255
// List of all update/insert operations, executed as second
256
nsClassHashtable<nsCStringHashKey, DBOperation> mUpdates;
257
258
// Collection of all tasks, valid only between Prepare() and Execute()
259
nsTArray<nsAutoPtr<DBOperation> > mExecList;
260
261
// Number of failing flush attempts
262
uint32_t mFlushFailureCount;
263
};
264
265
class ThreadObserver final : public nsIThreadObserver {
266
NS_DECL_THREADSAFE_ISUPPORTS
267
NS_DECL_NSITHREADOBSERVER
268
269
ThreadObserver()
270
: mHasPendingEvents(false), mMonitor("StorageThreadMonitor") {}
271
272
bool HasPendingEvents() {
273
mMonitor.AssertCurrentThreadOwns();
274
return mHasPendingEvents;
275
}
276
void ClearPendingEvents() {
277
mMonitor.AssertCurrentThreadOwns();
278
mHasPendingEvents = false;
279
}
280
Monitor& GetMonitor() { return mMonitor; }
281
282
private:
283
virtual ~ThreadObserver() {}
284
bool mHasPendingEvents;
285
// The monitor we drive the thread with
286
Monitor mMonitor;
287
};
288
289
class InitHelper;
290
291
class NoteBackgroundThreadRunnable;
292
293
class ShutdownRunnable : public Runnable {
294
// Only touched on the main thread.
295
bool& mDone;
296
297
public:
298
explicit ShutdownRunnable(bool& aDone)
299
: Runnable("dom::StorageDBThread::ShutdownRunnable"), mDone(aDone) {
300
MOZ_ASSERT(NS_IsMainThread());
301
}
302
303
private:
304
~ShutdownRunnable() {}
305
306
NS_DECL_NSIRUNNABLE
307
};
308
309
public:
310
StorageDBThread();
311
virtual ~StorageDBThread() {}
312
313
static StorageDBThread* Get();
314
315
static StorageDBThread* GetOrCreate(const nsString& aProfilePath);
316
317
static nsresult GetProfilePath(nsString& aProfilePath);
318
319
virtual nsresult Init(const nsString& aProfilePath);
320
321
// Flushes all uncommited data and stops the I/O thread.
322
virtual nsresult Shutdown();
323
324
virtual void AsyncPreload(LocalStorageCacheBridge* aCache,
325
bool aPriority = false) {
326
InsertDBOp(new DBOperation(
327
aPriority ? DBOperation::opPreloadUrgent : DBOperation::opPreload,
328
aCache));
329
}
330
331
virtual void SyncPreload(LocalStorageCacheBridge* aCache,
332
bool aForce = false);
333
334
virtual void AsyncGetUsage(StorageUsageBridge* aUsage) {
335
InsertDBOp(new DBOperation(DBOperation::opGetUsage, aUsage));
336
}
337
338
virtual nsresult AsyncAddItem(LocalStorageCacheBridge* aCache,
339
const nsAString& aKey,
340
const nsAString& aValue) {
341
return InsertDBOp(
342
new DBOperation(DBOperation::opAddItem, aCache, aKey, aValue));
343
}
344
345
virtual nsresult AsyncUpdateItem(LocalStorageCacheBridge* aCache,
346
const nsAString& aKey,
347
const nsAString& aValue) {
348
return InsertDBOp(
349
new DBOperation(DBOperation::opUpdateItem, aCache, aKey, aValue));
350
}
351
352
virtual nsresult AsyncRemoveItem(LocalStorageCacheBridge* aCache,
353
const nsAString& aKey) {
354
return InsertDBOp(new DBOperation(DBOperation::opRemoveItem, aCache, aKey));
355
}
356
357
virtual nsresult AsyncClear(LocalStorageCacheBridge* aCache) {
358
return InsertDBOp(new DBOperation(DBOperation::opClear, aCache));
359
}
360
361
virtual void AsyncClearAll() {
362
InsertDBOp(new DBOperation(DBOperation::opClearAll));
363
}
364
365
virtual void AsyncClearMatchingOrigin(const nsACString& aOriginNoSuffix) {
366
InsertDBOp(
367
new DBOperation(DBOperation::opClearMatchingOrigin, aOriginNoSuffix));
368
}
369
370
virtual void AsyncClearMatchingOriginAttributes(
371
const OriginAttributesPattern& aPattern) {
372
InsertDBOp(new DBOperation(DBOperation::opClearMatchingOriginAttributes,
373
aPattern));
374
}
375
376
virtual void AsyncFlush();
377
378
virtual bool ShouldPreloadOrigin(const nsACString& aOrigin);
379
380
// Get the complete list of scopes having data.
381
void GetOriginsHavingData(nsTArray<nsCString>* aOrigins);
382
383
private:
384
nsCOMPtr<nsIFile> mDatabaseFile;
385
PRThread* mThread;
386
387
// Used to observe runnables dispatched to our thread and to monitor it.
388
RefPtr<ThreadObserver> mThreadObserver;
389
390
// Flag to stop, protected by the monitor returned by
391
// mThreadObserver->GetMonitor().
392
bool mStopIOThread;
393
394
// Whether WAL is enabled
395
bool mWALModeEnabled;
396
397
// Whether DB has already been open, avoid races between main thread reads
398
// and pending DB init in the background I/O thread
399
Atomic<bool, ReleaseAcquire> mDBReady;
400
401
// State of the database initiation
402
nsresult mStatus;
403
404
// List of origins (including origin attributes suffix) having data, for
405
// optimization purposes only
406
nsTHashtable<nsCStringHashKey> mOriginsHavingData;
407
408
// Connection used by the worker thread for all read and write ops
409
nsCOMPtr<mozIStorageConnection> mWorkerConnection;
410
411
// Connection used only on the main thread for sync read operations
412
nsCOMPtr<mozIStorageConnection> mReaderConnection;
413
414
StatementCache mWorkerStatements;
415
StatementCache mReaderStatements;
416
417
// Time the first pending operation has been added to the pending operations
418
// list
419
TimeStamp mDirtyEpoch;
420
421
// Flag to force immediate flush of all pending operations
422
bool mFlushImmediately;
423
424
// List of preloading operations, in chronological or priority order.
425
// Executed prioritly over pending update operations.
426
nsTArray<DBOperation*> mPreloads;
427
428
// Collector of pending update operations
429
PendingOperations mPendingTasks;
430
431
// Counter of calls for thread priority rising.
432
int32_t mPriorityCounter;
433
434
// Helper to direct an operation to one of the arrays above;
435
// also checks IsOriginClearPending for preloads
436
nsresult InsertDBOp(DBOperation* aOperation);
437
438
// Opens the database, first thing we do after start of the thread.
439
nsresult OpenDatabaseConnection();
440
nsresult OpenAndUpdateDatabase();
441
nsresult InitDatabase();
442
nsresult ShutdownDatabase();
443
444
// Tries to establish WAL mode
445
nsresult SetJournalMode(bool aIsWal);
446
nsresult TryJournalMode();
447
448
// Sets the threshold for auto-checkpointing the WAL.
449
nsresult ConfigureWALBehavior();
450
451
void SetHigherPriority();
452
void SetDefaultPriority();
453
454
// Ensures we flush pending tasks in some reasonble time
455
void ScheduleFlush();
456
457
// Called when flush of pending tasks is being executed
458
void UnscheduleFlush();
459
460
// This method is used for two purposes:
461
// 1. as a value passed to monitor.Wait() method
462
// 2. as in indicator that flush has to be performed
463
//
464
// Return:
465
// - TimeDuration::Forever() when no pending tasks are scheduled
466
// - Non-zero TimeDuration when tasks have been scheduled, but it
467
// is still not time to perform the flush ; it is actual time to
468
// wait until the flush has to happen.
469
// - 0 TimeDuration when it is time to do the flush
470
TimeDuration TimeUntilFlush();
471
472
// Notifies to the main thread that flush has completed
473
void NotifyFlushCompletion();
474
475
// Thread loop
476
static void ThreadFunc(void* aArg);
477
void ThreadFunc();
478
};
479
480
} // namespace dom
481
} // namespace mozilla
482
483
#endif // mozilla_dom_StorageDBThread_h