WebCore:
authorbeidson <beidson@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 30 Aug 2006 08:11:17 +0000 (08:11 +0000)
committerbeidson <beidson@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 30 Aug 2006 08:11:17 +0000 (08:11 +0000)
        Reviewed by Kevin Decker (Sarge)

        <rdar://problem/4678414> - New IconDB needs to delete icons when asked
        <rdar://problem/4707718> - If user's Icon directory is unwritable, Safari will crash at startup

        * bridge/mac/WebCoreIconDatabaseBridge.h:
        * bridge/mac/WebCoreIconDatabaseBridge.mm:
        (-[WebCoreIconDatabaseBridge removeAllIcons]):  Added
        * loader/icon/IconDatabase.cpp:
        (WebCore::IconDatabase::open): If DB file is not writeable, create an in-memory DB for this session
        (WebCore::IconDatabase::close): Use new deleteAllPreparedStatements()
        (WebCore::IconDatabase::removeAllIcons): Actually implemented
        (WebCore::IconDatabase::deleteAllPreparedStatements): Added for convinience/consistency
        (WebCore::IconDatabase::setPrivateBrowsingEnabled): Use new SQLDatabase::clearAllTables()
        * loader/icon/IconDatabase.h:
        * loader/icon/SQLDatabase.cpp:
        (WebCore::SQLDatabase::clearAllTables): Moved this from IconDatabase as it actually belongs here
        (WebCore::SQLDatabase::vacuum): Added
        * loader/icon/SQLDatabase.h:
        (WebCore::SQLDatabase::path): changed name from getPath()

WebKit:

        Reviewed by Kevin Decker (Sarge)

        <rdar://problem/4678414> - New IconDB needs to delete icons when asked

        * Misc/WebIconDatabase.m:
        (-[WebIconDatabase removeAllIcons]): Call through to WebCore to remove icons, then send notification

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@16111 268f45cc-cd09-0410-ab3c-d52691b4dbfc

WebCore/ChangeLog
WebCore/bridge/mac/WebCoreIconDatabaseBridge.h
WebCore/bridge/mac/WebCoreIconDatabaseBridge.mm
WebCore/loader/icon/IconDatabase.cpp
WebCore/loader/icon/IconDatabase.h
WebCore/loader/icon/SQLDatabase.cpp
WebCore/loader/icon/SQLDatabase.h
WebKit/ChangeLog
WebKit/Misc/WebIconDatabase.m

index 0239265e6096062fbc79123f83753a6d58832952..0930edd379ca99ce90deb1b62516ead97ec04190 100644 (file)
@@ -1,3 +1,26 @@
+2006-08-29  Brady Eidson  <beidson@apple.com>
+
+        Reviewed by Kevin Decker (Sarge)
+
+        <rdar://problem/4678414> - New IconDB needs to delete icons when asked
+        <rdar://problem/4707718> - If user's Icon directory is unwritable, Safari will crash at startup
+
+        * bridge/mac/WebCoreIconDatabaseBridge.h:
+        * bridge/mac/WebCoreIconDatabaseBridge.mm:
+        (-[WebCoreIconDatabaseBridge removeAllIcons]):  Added
+        * loader/icon/IconDatabase.cpp:
+        (WebCore::IconDatabase::open): If DB file is not writeable, create an in-memory DB for this session
+        (WebCore::IconDatabase::close): Use new deleteAllPreparedStatements()
+        (WebCore::IconDatabase::removeAllIcons): Actually implemented
+        (WebCore::IconDatabase::deleteAllPreparedStatements): Added for convinience/consistency
+        (WebCore::IconDatabase::setPrivateBrowsingEnabled): Use new SQLDatabase::clearAllTables()
+        * loader/icon/IconDatabase.h:
+        * loader/icon/SQLDatabase.cpp:
+        (WebCore::SQLDatabase::clearAllTables): Moved this from IconDatabase as it actually belongs here
+        (WebCore::SQLDatabase::vacuum): Added
+        * loader/icon/SQLDatabase.h:
+        (WebCore::SQLDatabase::path): changed name from getPath()
+
 2006-08-29  Brady Eidson  <beidson@apple.com>
 
         Reviewed by Alice
index 55e2ae011611eca26a56ead4c5081703d5ce86bd..473ac14b695e72de476e723d1d6e4ff893df88a7 100644 (file)
@@ -43,6 +43,7 @@ typedef WebCore::IconDatabase WebCoreIconDatabase;
 - (BOOL)openSharedDatabaseWithPath:(NSString *)path;
 - (void)closeSharedDatabase;
 - (BOOL)isOpen;
+- (void)removeAllIcons;
 
 - (NSImage *)iconForPageURL:(NSString *)url withSize:(NSSize)size;
 - (NSString *)iconURLForPageURL:(NSString *)url;
index c23aa85ca73763801fcb598186d6ab8dac4037b7..047eb25d341942a9ad8bef4190ccf68e1128b4dd 100644 (file)
@@ -68,6 +68,12 @@ void WebCore::IconDatabase::loadIconFromURL(const String& url)
     return _iconDB != 0;
 }
 
+- (void)removeAllIcons
+{
+    if (_iconDB)
+        _iconDB->removeAllIcons();
+}
+
 - (BOOL)_isEmpty
 {
     return _iconDB ? _iconDB->isEmpty() : NO;
index 206c4fefe8851394b032dca379b2f86ae81e9df8..594f33f3835283561fd172d7607954ed198bd46d 100644 (file)
@@ -104,16 +104,19 @@ bool IconDatabase::open(const String& databasePath)
     else
         dbFilename = databasePath + "/" + defaultDatabaseFilename();
 
-    // Now, we'll see if we can open the on-disk table
-    // If we can't, this ::open() failed and we should bail now
+    // <rdar://problem/4707718> - If user's Icon directory is unwritable, Safari will crash at startup
+    // Now, we'll see if we can open the on-disk database.  If we can't, we'll log the error and open it as
+    // an in-memory database so the user will have icons during their current browsing session
+    
     if (!m_mainDB.open(dbFilename)) {
-        LOG(IconDatabase, "Unable to open icon database at path %s", dbFilename.ascii().data());
-        return false;
+        LOG_ERROR("Unable to open icon database at path %s - %s", dbFilename.ascii().data(), m_mainDB.lastErrorMsg());
+        if (!m_mainDB.open(":memory:"))
+            LOG_ERROR("Unable to open in-memory database for browsing - %s", m_mainDB.lastErrorMsg());
     }
     
     if (!isValidDatabase(m_mainDB)) {
         LOG(IconDatabase, "%s is missing or in an invalid state - reconstructing", dbFilename.ascii().data());
-        clearDatabaseTables(m_mainDB);
+        m_mainDB.clearAllTables();
         createDatabaseTables(m_mainDB);
     }
 
@@ -132,7 +135,7 @@ bool IconDatabase::open(const String& databasePath)
     
     // Open the in-memory table for private browsing
     if (!m_privateBrowsingDB.open(":memory:"))
-        LOG_ERROR("Unabled to open in-memory database for private browsing - %s", m_privateBrowsingDB.lastErrorMsg());
+        LOG_ERROR("Unable to open in-memory database for private browsing - %s", m_privateBrowsingDB.lastErrorMsg());
 
     // Only if we successfully remained open will we start our "initial purge timer"
     // rdar://4690949 - when we have deferred reads and writes all the way in, the prunetimer
@@ -146,22 +149,83 @@ bool IconDatabase::open(const String& databasePath)
 
 void IconDatabase::close()
 {
-    delete m_initialPruningTransaction;
-    if (m_preparedPageRetainInsertStatement)
-        m_preparedPageRetainInsertStatement->finalize();
+    // This will close all the SQL statements and transactions we have open,
+    // syncing the DB at the appropriate point
+    deleteAllPreparedStatements(true);
+    m_mainDB.close();
+    m_privateBrowsingDB.close();
+}
+
+void IconDatabase::removeAllIcons()
+{
+    // We don't need to sync anything anymore since we're wiping everything.  
+    // So we can kill the update timer, and clear all the hashes of "items that need syncing"
+    m_updateTimer.stop();
+    m_iconDataCachesPendingUpdate.clear();
+    m_pageURLsPendingAddition.clear();
+    m_pageURLsPendingDeletion.clear();
+    m_iconURLsPendingDeletion.clear();
+    
+    //  Now clear all in-memory URLs and Icons
+    m_pageURLToIconURLMap.clear();
+    m_pageURLToRetainCount.clear();
+    m_iconURLToRetainCount.clear();
+    
+    HashMap<String, IconDataCache*>::iterator i = m_iconURLToIconDataCacheMap.begin();
+    HashMap<String, IconDataCache*>::iterator end = m_iconURLToIconDataCacheMap.end();
+    for (; i != end; ++i)
+        delete i->second;
+    m_iconURLToIconDataCacheMap.clear();
+        
+    // Wipe any pre-prepared statements, otherwise resetting the SQLDatabases themselves will fail
+    deleteAllPreparedStatements(false);
+    
+    // The easiest way to wipe the in-memory database is by closing and reopening it
+    m_privateBrowsingDB.close();
+    if (!m_privateBrowsingDB.open(":memory:"))
+        LOG_ERROR("Unable to open in-memory database for private browsing - %s", m_privateBrowsingDB.lastErrorMsg());
+    createDatabaseTables(m_privateBrowsingDB);
+        
+    // To reset the on-disk database, we'll wipe all its tables then vacuum it
+    // This is easier and safer than closing it, deleting the file, and recreating from scratch
+    m_mainDB.clearAllTables();
+    m_mainDB.runVacuumCommand();
+    createDatabaseTables(m_mainDB);
+}
+
+// There are two instances where you'd want to deleteAllPreparedStatements - one with sync, and one without
+// A - Closing down the database on application exit - in this case, you *do* want to save the icons out
+// B - Resetting the DB via removeAllIcons() - in this case, you *don't* want to sync, because it would be a waste of time
+void IconDatabase::deleteAllPreparedStatements(bool withSync)
+{
+    // Must wipe the initial retain statement before the initial transaction
     delete m_preparedPageRetainInsertStatement;
+    m_preparedPageRetainInsertStatement = 0;
+    delete m_initialPruningTransaction;
+    m_initialPruningTransaction = 0;
 
-    syncDatabase();
+    // Sync, if desired
+    if (withSync)
+        syncDatabase();
+        
+    // Order doesn't matter on these
     delete m_timeStampForIconURLStatement;
+    m_timeStampForIconURLStatement = 0;
     delete m_iconURLForPageURLStatement;
+    m_iconURLForPageURLStatement = 0;
     delete m_hasIconForIconURLStatement;
+    m_hasIconForIconURLStatement = 0;
     delete m_forgetPageURLStatement;
+    m_forgetPageURLStatement = 0;
     delete m_setIconIDForPageURLStatement;
+    m_setIconIDForPageURLStatement = 0;
     delete m_getIconIDForIconURLStatement;
+    m_getIconIDForIconURLStatement = 0;
     delete m_addIconForIconURLStatement;
+    m_addIconForIconURLStatement = 0;
     delete m_imageDataForIconURLStatement;
-    m_mainDB.close();
-    m_privateBrowsingDB.close();
+    m_imageDataForIconURLStatement = 0;
 }
 
 bool IconDatabase::isEmpty()
@@ -187,22 +251,6 @@ bool IconDatabase::isValidDatabase(SQLDatabase& db)
     return true;
 }
 
-void IconDatabase::clearDatabaseTables(SQLDatabase& db)
-{
-    String query = "SELECT name FROM sqlite_master WHERE type='table';";
-    Vector<String> tables;
-    if (!SQLStatement(db, query).returnTextResults16(0, tables)) {
-        LOG(IconDatabase, "Unable to retrieve list of tables from database");
-        return;
-    }
-    
-    for (Vector<String>::iterator table = tables.begin(); table != tables.end(); ++table ) {
-        if (!db.executeCommand("DROP TABLE " + *table)) {
-            LOG(IconDatabase, "Unable to drop table %s", (*table).ascii().data());
-        }
-    }
-}
-
 void IconDatabase::createDatabaseTables(SQLDatabase& db)
 {
     if (!db.executeCommand("CREATE TABLE PageURL (url TEXT NOT NULL ON CONFLICT FAIL UNIQUE ON CONFLICT REPLACE,iconID INTEGER NOT NULL ON CONFLICT FAIL);")) {
@@ -254,7 +302,7 @@ void IconDatabase::setPrivateBrowsingEnabled(bool flag)
         createDatabaseTables(m_privateBrowsingDB);
         m_currentDB = &m_privateBrowsingDB;
     } else {
-        clearDatabaseTables(m_privateBrowsingDB);
+        m_privateBrowsingDB.clearAllTables();
         m_currentDB = &m_mainDB;
     }
 }
index 9f5c2fb5bb90741446807bc28af6f19b4eb5527e..0ab7758e19bda786a5db4935ddb5c8149e52755a 100644 (file)
@@ -65,6 +65,8 @@ public:
     bool isOpen() { return m_mainDB.isOpen() && m_privateBrowsingDB.isOpen(); }
     void close();
     
+    void removeAllIcons();
+    
     bool isEmpty();
  
     Image* iconForPageURL(const String&, const IntSize&, bool cache = true);
@@ -112,10 +114,7 @@ private:
     void forgetIconForIconURLFromDatabase(const String&);
     
     void setIconURLForPageURLInDatabase(const String&, const String&);
-    
-    // Wipe all icons from the DB
-    void removeAllIcons();
-    
+        
     // Called by the startup timer, this method removes all icons that are unretained
     // after initial retains are complete, and pageURLs that are dangling
     void pruneUnretainedIconsOnStartup(Timer<IconDatabase>*);
@@ -132,10 +131,7 @@ private:
     
     // Do a quick check to make sure the database tables are in place and the db version is current
     bool isValidDatabase(SQLDatabase&);
-    
-    // Delete all tables from the given database
-    void clearDatabaseTables(SQLDatabase&);
-    
+        
     // Create the tables and triggers for the given database.
     void createDatabaseTables(SQLDatabase&);
     
@@ -183,6 +179,7 @@ private:
     void imageDataForIconURLQuery(SQLDatabase& db, const String& iconURL, Vector<unsigned char>& result);
     SQLStatement *m_imageDataForIconURLStatement;
 
+    void deleteAllPreparedStatements(bool withSync);
 
     // FIXME: This method is currently implemented in WebCoreIconDatabaseBridge so we can be in ObjC++ and fire off a loader in Webkit
     // Once all of the loader logic is sufficiently moved into WebCore we need to move this implementation to IconDatabase.cpp
index 3b368167a26012fcc65334b8147a3d84d41ef124..4b595a76f3bebd8acc3ba150b32163db89137833 100644 (file)
@@ -119,6 +119,29 @@ bool SQLDatabase::tableExists(const String& tablename)
     return sql.step() == SQLITE_ROW;
 }
 
+void SQLDatabase::clearAllTables()
+{
+    String query = "SELECT name FROM sqlite_master WHERE type='table';";
+    Vector<String> tables;
+    if (!SQLStatement(*this, query).returnTextResults16(0, tables)) {
+        LOG(IconDatabase, "Unable to retrieve list of tables from database");
+        return;
+    }
+    
+    for (Vector<String>::iterator table = tables.begin(); table != tables.end(); ++table ) {
+        if (*table == "sqlite_sequence")
+            continue;
+        if (!executeCommand("DROP TABLE " + *table))
+            LOG(IconDatabase, "Unable to drop table %s", (*table).ascii().data());
+    }
+}
+
+void SQLDatabase::runVacuumCommand()
+{
+    if (!executeCommand("VACUUM;"))
+        LOG(IconDatabase, "Unable to vacuum database - %s", lastErrorMsg());
+}
+
 int64_t SQLDatabase::lastInsertRowID()
 {
     if (!m_db)
index 4a7b1197a93485a66f968c9e39ead91188d4cb15..7744d6fedd1faa1d3830d690806958976e83bf2b 100644 (file)
@@ -43,13 +43,15 @@ public:
 
     bool open(const String& filename);
     bool isOpen() { return m_db; }
-    String getPath(){ return m_path; }
+    String path(){ return m_path; }
     void close();
 
     bool executeCommand(const String&);
     bool returnsAtLeastOneResult(const String&);
     
     bool tableExists(const String&);
+    void clearAllTables();
+    void runVacuumCommand();
     
     int64_t lastInsertRowID();
 
index ea4aeac4f3439609c0eb466a8859755e6bc11b7f..f7b275116b6c55efcd4fba57a85d24132f3f2d02 100644 (file)
@@ -1,3 +1,12 @@
+2006-08-29  Brady Eidson  <beidson@apple.com>
+
+        Reviewed by Kevin Decker (Sarge)
+
+        <rdar://problem/4678414> - New IconDB needs to delete icons when asked
+
+        * Misc/WebIconDatabase.m:
+        (-[WebIconDatabase removeAllIcons]): Call through to WebCore to remove icons, then send notification
+
 2006-08-29  Brady Eidson  <beidson@apple.com>
 
         Reviewed by Alice
index 06cb6cf558e12b05e39f8900c2a4badeca46059a..432de26c73867885c2c7814c0e2879409e3c93c4 100644 (file)
@@ -189,8 +189,16 @@ NSSize WebIconLargeSize = {128, 128};
 
 - (void)removeAllIcons
 {
-    // FIXME - <rdar://problem/4678414>
-    // Need to create a bridge method that calls through to WebCore and performs a wipe of the DB there
+    // <rdar://problem/4678414> - New IconDB needs to delete icons when asked
+
+    if (![self _isEnabled])
+        return;
+        
+    [_private->databaseBridge removeAllIcons];
+
+    [[NSNotificationCenter defaultCenter] postNotificationName:WebIconDatabaseDidRemoveAllIconsNotification
+                                                        object:self
+                                                      userInfo:nil];
 }
 
 - (BOOL)isIconExpiredForIconURL:(NSString *)iconURL