File: IconDatabase.h

package info (click to toggle)
webkit2gtk 2.18.6-1~bpo8%2B1
  • links: PTS, VCS
  • area: main
  • in suites: jessie-backports-sloppy
  • size: 159,076 kB
  • sloc: cpp: 1,636,147; ansic: 45,350; python: 14,988; perl: 13,794; ruby: 9,803; xml: 9,342; asm: 5,312; yacc: 2,167; lex: 1,007; sh: 773; makefile: 63
file content (389 lines) | stat: -rw-r--r-- 13,801 bytes parent folder | download | duplicates (2)
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
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
/*
 * Copyright (C) 2006, 2007, 2008, 2009, 2014 Apple Inc. All rights reserved.
 * Copyright (C) 2007 Justin Haygood (jhaygood@reaktix.com)
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#pragma once

#include <WebCore/NativeImage.h>
#include <WebCore/SQLiteDatabase.h>
#include <wtf/Condition.h>
#include <wtf/HashCountedSet.h>
#include <wtf/HashMap.h>
#include <wtf/HashSet.h>
#include <wtf/RunLoop.h>
#include <wtf/glib/RunLoopSourcePriority.h>
#include <wtf/text/StringHash.h>
#include <wtf/text/WTFString.h>

namespace WebCore {
class SharedBuffer;
}

namespace WebKit {

class IconDatabaseClient {
public:
    virtual ~IconDatabaseClient() = default;

    virtual void didImportIconURLForPageURL(const String&) { }
    virtual void didImportIconDataForPageURL(const String&) { }
    virtual void didChangeIconForPageURL(const String&) { }
    virtual void didFinishURLImport() { }
};

class IconDatabase {
    WTF_MAKE_FAST_ALLOCATED;

private:
    class IconSnapshot {
    public:
        IconSnapshot() = default;

        IconSnapshot(const String& iconURL, int timestamp, WebCore::SharedBuffer* data)
            : m_iconURL(iconURL)
            , m_timestamp(timestamp)
            , m_data(data)
        { }

        const String& iconURL() const { return m_iconURL; }
        int timestamp() const { return m_timestamp; }
        WebCore::SharedBuffer* data() const { return m_data.get(); }

    private:
        String m_iconURL;
        int m_timestamp { 0 };
        RefPtr<WebCore::SharedBuffer> m_data;
    };

    class IconRecord : public RefCounted<IconRecord> {
    public:
        static Ref<IconRecord> create(const String& url)
        {
            return adoptRef(*new IconRecord(url));
        }
        ~IconRecord();

        time_t getTimestamp() { return m_stamp; }
        void setTimestamp(time_t stamp) { m_stamp = stamp; }

        void setImageData(RefPtr<WebCore::SharedBuffer>&&);
        WebCore::NativeImagePtr image(const WebCore::IntSize&);

        String iconURL() { return m_iconURL; }

        enum class ImageDataStatus { Present, Missing, Unknown };
        ImageDataStatus imageDataStatus();

        HashSet<String>& retainingPageURLs() { return m_retainingPageURLs; }

        IconSnapshot snapshot(bool forDeletion = false) const;

    private:
        IconRecord(const String& url);

        String m_iconURL;
        time_t m_stamp { 0 };
        RefPtr<WebCore::SharedBuffer> m_imageData;
        WebCore::NativeImagePtr m_image;

        HashSet<String> m_retainingPageURLs;

        // This allows us to cache whether or not a SiteIcon has had its data set yet
        // This helps the IconDatabase know if it has to set the data on a new object or not,
        // and also to determine if the icon is missing data or if it just hasn't been brought
        // in from the DB yet
        bool m_dataSet { false };
    };

    class PageURLSnapshot {
    public:
        PageURLSnapshot() = default;

        PageURLSnapshot(const String& pageURL, const String& iconURL)
            : m_pageURL(pageURL)
            , m_iconURL(iconURL)
        { }

        const String& pageURL() const { return m_pageURL; }
        const String& iconURL() const { return m_iconURL; }

    private:
        String m_pageURL;
        String m_iconURL;
    };

    class PageURLRecord {
        WTF_MAKE_NONCOPYABLE(PageURLRecord); WTF_MAKE_FAST_ALLOCATED;
    public:
        PageURLRecord(const String& pageURL);
        ~PageURLRecord();

        inline String url() const { return m_pageURL; }

        void setIconRecord(RefPtr<IconRecord>&&);
        IconRecord* iconRecord() { return m_iconRecord.get(); }

        PageURLSnapshot snapshot(bool forDeletion = false) const;

        // Returns false if the page wasn't retained beforehand, true if the retain count was already 1 or higher.
        bool retain(int count)
        {
            bool wasRetained = m_retainCount > 0;
            m_retainCount += count;
            return wasRetained;
        }

        // Returns true if the page is still retained after the call. False if the retain count just dropped to 0.
        bool release(int count)
        {
            ASSERT(m_retainCount >= count);
            m_retainCount -= count;
            return m_retainCount > 0;
        }

        int retainCount() const { return m_retainCount; }

    private:
        String m_pageURL;
        RefPtr<IconRecord> m_iconRecord;
        int m_retainCount { 0 };
    };

    class MainThreadNotifier {
    public:
        MainThreadNotifier()
            : m_timer(RunLoop::main(), this, &MainThreadNotifier::timerFired)
        {
            m_timer.setPriority(RunLoopSourcePriority::MainThreadDispatcherTimer);
        }

        void setActive(bool active)
        {
            m_isActive.store(active);
        }

        void notify(Function<void()>&& notification)
        {
            if (!m_isActive.load())
                return;

            {
                LockHolder locker(m_notificationQueueLock);
                m_notificationQueue.append(WTFMove(notification));
            }

            if (!m_timer.isActive())
                m_timer.startOneShot(0_s);
        }

        void stop()
        {
            setActive(false);
            m_timer.stop();
            LockHolder locker(m_notificationQueueLock);
            m_notificationQueue.clear();
        }

    private:
        void timerFired()
        {
            Deque<Function<void()>> notificationQueue;
            {
                LockHolder locker(m_notificationQueueLock);
                notificationQueue = WTFMove(m_notificationQueue);
            }

            if (!m_isActive.load())
                return;

            while (!notificationQueue.isEmpty()) {
                auto function = notificationQueue.takeFirst();
                function();
            }
        }

        Deque<Function<void()>> m_notificationQueue;
        Lock m_notificationQueueLock;
        Atomic<bool> m_isActive;
        RunLoop::Timer<MainThreadNotifier> m_timer;
    };

// *** Main Thread Only ***
public:
    IconDatabase();
    ~IconDatabase();

    enum class IconLoadDecision { Yes, No, Unknown };

    void setClient(std::unique_ptr<IconDatabaseClient>&&);

    bool open(const String& directory, const String& filename);
    void close();

    void removeAllIcons();

    void retainIconForPageURL(const String&);
    void releaseIconForPageURL(const String&);
    void setIconDataForIconURL(RefPtr<WebCore::SharedBuffer>&&, const String& iconURL);
    void setIconURLForPageURL(const String& iconURL, const String& pageURL);

    enum class IsKnownIcon { No, Yes };
    std::pair<WebCore::NativeImagePtr, IsKnownIcon> synchronousIconForPageURL(const String&, const WebCore::IntSize&);
    String synchronousIconURLForPageURL(const String&);
    bool synchronousIconDataKnownForIconURL(const String&);
    IconLoadDecision synchronousLoadDecisionForIconURL(const String&);

    void setEnabled(bool);
    bool isEnabled() const;

    void setPrivateBrowsingEnabled(bool flag);
    bool isPrivateBrowsingEnabled() const;

    static void delayDatabaseCleanup();
    static void allowDatabaseCleanup();
    static void checkIntegrityBeforeOpening();

private:
    void wakeSyncThread();
    void scheduleOrDeferSyncTimer();
    void syncTimerFired();

    RunLoop::Timer<IconDatabase> m_syncTimer;
    RefPtr<Thread> m_syncThread;
    bool m_syncThreadRunning { false };
    bool m_scheduleOrDeferSyncTimerRequested { false };

// *** Any Thread ***
public:
    bool isOpen() const;
    String databasePath() const;
    static String defaultDatabaseFilename();

private:
    Ref<IconRecord> getOrCreateIconRecord(const String& iconURL);
    PageURLRecord* getOrCreatePageURLRecord(const String& pageURL);

    bool m_isEnabled {false };
    bool m_privateBrowsingEnabled { false };

    mutable Lock m_syncLock;
    Condition m_syncCondition;
    String m_databaseDirectory;
    // Holding m_syncLock is required when accessing m_completeDatabasePath
    String m_completeDatabasePath;

    bool m_threadTerminationRequested { false };
    bool m_removeIconsRequested { false };
    bool m_iconURLImportComplete { false };
    bool m_syncThreadHasWorkToDo { false };

    Lock m_urlAndIconLock;
    // Holding m_urlAndIconLock is required when accessing any of the following data structures or the objects they contain
    HashMap<String, IconRecord*> m_iconURLToRecordMap;
    HashMap<String, PageURLRecord*> m_pageURLToRecordMap;
    HashSet<String> m_retainedPageURLs;

    Lock m_pendingSyncLock;
    // Holding m_pendingSyncLock is required when accessing any of the following data structures
    HashMap<String, PageURLSnapshot> m_pageURLsPendingSync;
    HashMap<String, IconSnapshot> m_iconsPendingSync;

    Lock m_pendingReadingLock;
    // Holding m_pendingSyncLock is required when accessing any of the following data structures - when dealing with IconRecord*s, holding m_urlAndIconLock is also required
    HashSet<String> m_pageURLsPendingImport;
    HashSet<String> m_pageURLsInterestedInIcons;
    HashSet<IconRecord*> m_iconsPendingReading;

    Lock m_urlsToRetainOrReleaseLock;
    // Holding m_urlsToRetainOrReleaseLock is required when accessing any of the following data structures.
    HashCountedSet<String> m_urlsToRetain;
    HashCountedSet<String> m_urlsToRelease;
    bool m_retainOrReleaseIconRequested { false };

// *** Sync Thread Only ***
public:
    bool shouldStopThreadActivity() const;

private:
    void iconDatabaseSyncThread();

    // The following block of methods are called exclusively by the sync thread to manage i/o to and from the database
    // Each method should periodically monitor m_threadTerminationRequested when it makes sense to return early on shutdown
    void performOpenInitialization();
    bool checkIntegrity();
    void performURLImport();
    void syncThreadMainLoop();
    bool readFromDatabase();
    bool writeToDatabase();
    void pruneUnretainedIcons();
    void checkForDanglingPageURLs(bool pruneIfFound);
    void removeAllIconsOnThread();
    void deleteAllPreparedStatements();
    void* cleanupSyncThread();
    void performRetainIconForPageURL(const String&, int retainCount);
    void performReleaseIconForPageURL(const String&, int releaseCount);

    bool m_initialPruningComplete { false };

    void setIconURLForPageURLInSQLDatabase(const String&, const String&);
    void setIconIDForPageURLInSQLDatabase(int64_t, const String&);
    void removePageURLFromSQLDatabase(const String& pageURL);
    int64_t getIconIDForIconURLFromSQLDatabase(const String& iconURL);
    int64_t addIconURLToSQLDatabase(const String&);
    RefPtr<WebCore::SharedBuffer> getImageDataForIconURLFromSQLDatabase(const String& iconURL);
    void removeIconFromSQLDatabase(const String& iconURL);
    void writeIconSnapshotToSQLDatabase(const IconSnapshot&);

    void performPendingRetainAndReleaseOperations();

    // Methods to dispatch client callbacks on the main thread
    void dispatchDidImportIconURLForPageURLOnMainThread(const String&);
    void dispatchDidImportIconDataForPageURLOnMainThread(const String&);
    void dispatchDidFinishURLImportOnMainThread();

    // The client is set by the main thread before the thread starts, and from then on is only used by the sync thread
    std::unique_ptr<IconDatabaseClient> m_client;

    WebCore::SQLiteDatabase m_syncDB;

    std::unique_ptr<WebCore::SQLiteStatement> m_setIconIDForPageURLStatement;
    std::unique_ptr<WebCore::SQLiteStatement> m_removePageURLStatement;
    std::unique_ptr<WebCore::SQLiteStatement> m_getIconIDForIconURLStatement;
    std::unique_ptr<WebCore::SQLiteStatement> m_getImageDataForIconURLStatement;
    std::unique_ptr<WebCore::SQLiteStatement> m_addIconToIconInfoStatement;
    std::unique_ptr<WebCore::SQLiteStatement> m_addIconToIconDataStatement;
    std::unique_ptr<WebCore::SQLiteStatement> m_getImageDataStatement;
    std::unique_ptr<WebCore::SQLiteStatement> m_deletePageURLsForIconURLStatement;
    std::unique_ptr<WebCore::SQLiteStatement> m_deleteIconFromIconInfoStatement;
    std::unique_ptr<WebCore::SQLiteStatement> m_deleteIconFromIconDataStatement;
    std::unique_ptr<WebCore::SQLiteStatement> m_updateIconInfoStatement;
    std::unique_ptr<WebCore::SQLiteStatement> m_updateIconDataStatement;
    std::unique_ptr<WebCore::SQLiteStatement> m_setIconInfoStatement;
    std::unique_ptr<WebCore::SQLiteStatement> m_setIconDataStatement;

    MainThreadNotifier m_mainThreadNotifier;
};

} // namespace WebKit