Title: [145238] trunk/Source
Revision
145238
Author
jsb...@chromium.org
Date
2013-03-08 10:06:23 -0800 (Fri, 08 Mar 2013)

Log Message

IndexedDB: Use WeakPtr for Factory-to-BackingStore reference
https://bugs.webkit.org/show_bug.cgi?id=111459

Reviewed by Adam Barth.

Source/WebCore:

IDBFactoryBackendImpl maintains a map of backing stores - if another database in the same
origin is opened, the backing store instance must be re-used). This was a map to raw
pointers so that the backing store can be collected when all database references are
dropped. The map was maintained manually by passing the factory to the IDBBackingStore which
would add/remove itself on creation/destruction.

Replace this with a HashMap<WeakPtr<T>>. This simplifies the plumbing; map entries
"leak" but are purged on subsequent opens.

Added webkit_unit_test (Chromium port) to verify refcounts.

* Modules/indexeddb/IDBBackingStore.cpp:
(WebCore::IDBBackingStore::IDBBackingStore): No need to notify factory of lifetime.
(WebCore::IDBBackingStore::~IDBBackingStore): Ditto.
(WebCore::IDBBackingStore::open): Ditto.
* Modules/indexeddb/IDBBackingStore.h: No reference to the factory, but...
(WebCore::IDBBackingStore::createWeakPtr): Do need to expose weak pointers for the factory to hold.
* Modules/indexeddb/IDBFactoryBackendImpl.cpp:
(WebCore::cleanWeakMap): Helper function to scrub a HashMap<WeakPtr<T>> of empty pointers.
May move to WTF when we've learned how general it is, or come up with a dedicated WeakPtrHashMap type.
(WebCore::IDBFactoryBackendImpl::openBackingStore): WeakPtr fu.
* Modules/indexeddb/IDBFactoryBackendImpl.h:
(IDBFactoryBackendImpl): Remove plumbing methods.

Source/WebKit/chromium:

Add new test that verifies refcounts.

* WebKit.gyp: Don't include files depending on webkit_support.
* tests/IDBBackingStoreTest.cpp:
(WebCore::IDBBackingStoreTest::SetUp): No need for dummy factory.
(MockIDBFactoryBackend): Allow access to protected openBackingStore method.
(WebCore::TEST): Add new test that verifies refcounts.
* tests/IDBCleanupOnIOErrorTest.cpp:
(WebCore::TEST): No need for dummy factory.

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (145237 => 145238)


--- trunk/Source/WebCore/ChangeLog	2013-03-08 17:42:13 UTC (rev 145237)
+++ trunk/Source/WebCore/ChangeLog	2013-03-08 18:06:23 UTC (rev 145238)
@@ -1,3 +1,34 @@
+2013-03-08  Joshua Bell  <jsb...@chromium.org>
+
+        IndexedDB: Use WeakPtr for Factory-to-BackingStore reference
+        https://bugs.webkit.org/show_bug.cgi?id=111459
+
+        Reviewed by Adam Barth.
+
+        IDBFactoryBackendImpl maintains a map of backing stores - if another database in the same
+        origin is opened, the backing store instance must be re-used). This was a map to raw
+        pointers so that the backing store can be collected when all database references are
+        dropped. The map was maintained manually by passing the factory to the IDBBackingStore which
+        would add/remove itself on creation/destruction.
+
+        Replace this with a HashMap<WeakPtr<T>>. This simplifies the plumbing; map entries
+        "leak" but are purged on subsequent opens.
+
+        Added webkit_unit_test (Chromium port) to verify refcounts.
+
+        * Modules/indexeddb/IDBBackingStore.cpp:
+        (WebCore::IDBBackingStore::IDBBackingStore): No need to notify factory of lifetime.
+        (WebCore::IDBBackingStore::~IDBBackingStore): Ditto.
+        (WebCore::IDBBackingStore::open): Ditto.
+        * Modules/indexeddb/IDBBackingStore.h: No reference to the factory, but...
+        (WebCore::IDBBackingStore::createWeakPtr): Do need to expose weak pointers for the factory to hold.
+        * Modules/indexeddb/IDBFactoryBackendImpl.cpp:
+        (WebCore::cleanWeakMap): Helper function to scrub a HashMap<WeakPtr<T>> of empty pointers.
+        May move to WTF when we've learned how general it is, or come up with a dedicated WeakPtrHashMap type.
+        (WebCore::IDBFactoryBackendImpl::openBackingStore): WeakPtr fu.
+        * Modules/indexeddb/IDBFactoryBackendImpl.h:
+        (IDBFactoryBackendImpl): Remove plumbing methods.
+
 2013-03-08  John Mellor  <joh...@chromium.org>
 
         @media queries do not take zooming into account

Modified: trunk/Source/WebCore/Modules/indexeddb/IDBBackingStore.cpp (145237 => 145238)


--- trunk/Source/WebCore/Modules/indexeddb/IDBBackingStore.cpp	2013-03-08 17:42:13 UTC (rev 145237)
+++ trunk/Source/WebCore/Modules/indexeddb/IDBBackingStore.cpp	2013-03-08 18:06:23 UTC (rev 145238)
@@ -30,7 +30,6 @@
 
 #include "FileSystem.h"
 #include "HistogramSupport.h"
-#include "IDBFactoryBackendImpl.h"
 #include "IDBKey.h"
 #include "IDBKeyPath.h"
 #include "IDBKeyRange.h"
@@ -44,9 +43,6 @@
 #include "LevelDBTransaction.h"
 #include "SecurityOrigin.h"
 #include "SharedBuffer.h"
-#if PLATFORM(CHROMIUM)
-#include <public/Platform.h>
-#endif
 #include <wtf/Assertions.h>
 
 namespace WebCore {
@@ -339,28 +335,20 @@
     }
 };
 
-IDBBackingStore::IDBBackingStore(const String& identifier, IDBFactoryBackendImpl* factory, PassOwnPtr<LevelDBDatabase> db)
+IDBBackingStore::IDBBackingStore(const String& identifier, PassOwnPtr<LevelDBDatabase> db)
     : m_identifier(identifier)
-    , m_factory(factory)
     , m_db(db)
+    , m_weakFactory(this)
 {
-#if PLATFORM(CHROMIUM)
-    ASSERT(m_factory || WebKit::Platform::current()->unitTestSupport());
-#endif
-    if (m_factory)
-        m_factory->addIDBBackingStore(identifier, this);
 }
 
 IDBBackingStore::IDBBackingStore()
+    : m_weakFactory(this)
 {
 }
 
 IDBBackingStore::~IDBBackingStore()
 {
-    // Only null in tests.
-    if (m_factory)
-        m_factory->removeIDBBackingStore(m_identifier);
-
     // m_db's destructor uses m_comparator. The order of destruction is important.
     m_db.clear();
     m_comparator.clear();
@@ -380,13 +368,13 @@
     IDBLevelDBBackingStoreOpenMax,
 };
 
-PassRefPtr<IDBBackingStore> IDBBackingStore::open(SecurityOrigin* securityOrigin, const String& pathBaseArg, const String& fileIdentifier, IDBFactoryBackendImpl* factory)
+PassRefPtr<IDBBackingStore> IDBBackingStore::open(SecurityOrigin* securityOrigin, const String& pathBaseArg, const String& fileIdentifier)
 {
     DefaultLevelDBFactory levelDBFactory;
-    return IDBBackingStore::open(securityOrigin, pathBaseArg, fileIdentifier, factory, &levelDBFactory);
+    return IDBBackingStore::open(securityOrigin, pathBaseArg, fileIdentifier, &levelDBFactory);
 }
 
-PassRefPtr<IDBBackingStore> IDBBackingStore::open(SecurityOrigin* securityOrigin, const String& pathBaseArg, const String& fileIdentifier, IDBFactoryBackendImpl* factory, LevelDBFactory* levelDBFactory)
+PassRefPtr<IDBBackingStore> IDBBackingStore::open(SecurityOrigin* securityOrigin, const String& pathBaseArg, const String& fileIdentifier, LevelDBFactory* levelDBFactory)
 {
     IDB_TRACE("IDBBackingStore::open");
     String pathBase = pathBaseArg;
@@ -456,7 +444,7 @@
 
     // FIXME: Handle comparator name changes.
 
-    RefPtr<IDBBackingStore> backingStore(adoptRef(new IDBBackingStore(fileIdentifier, factory, db.release())));
+    RefPtr<IDBBackingStore> backingStore(adoptRef(new IDBBackingStore(fileIdentifier, db.release())));
     backingStore->m_comparator = comparator.release();
 
     if (!setUpMetadata(backingStore->m_db.get(), fileIdentifier))

Modified: trunk/Source/WebCore/Modules/indexeddb/IDBBackingStore.h (145237 => 145238)


--- trunk/Source/WebCore/Modules/indexeddb/IDBBackingStore.h	2013-03-08 17:42:13 UTC (rev 145237)
+++ trunk/Source/WebCore/Modules/indexeddb/IDBBackingStore.h	2013-03-08 18:06:23 UTC (rev 145238)
@@ -34,13 +34,13 @@
 #include "LevelDBTransaction.h"
 #include <wtf/OwnPtr.h>
 #include <wtf/RefCounted.h>
+#include <wtf/WeakPtr.h>
 
 namespace WebCore {
 
 class LevelDBComparator;
 class LevelDBDatabase;
 class LevelDBTransaction;
-class IDBFactoryBackendImpl;
 class IDBKey;
 class IDBKeyRange;
 class SecurityOrigin;
@@ -57,8 +57,9 @@
     class Transaction;
 
     virtual ~IDBBackingStore();
-    static PassRefPtr<IDBBackingStore> open(SecurityOrigin*, const String& pathBase, const String& fileIdentifier, IDBFactoryBackendImpl*);
-    static PassRefPtr<IDBBackingStore> open(SecurityOrigin*, const String& pathBase, const String& fileIdentifier, IDBFactoryBackendImpl*, LevelDBFactory*);
+    static PassRefPtr<IDBBackingStore> open(SecurityOrigin*, const String& pathBase, const String& fileIdentifier);
+    static PassRefPtr<IDBBackingStore> open(SecurityOrigin*, const String& pathBase, const String& fileIdentifier, LevelDBFactory*);
+    WeakPtr<IDBBackingStore> createWeakPtr() { return m_weakFactory.createWeakPtr(); }
 
     virtual Vector<String> getDatabaseNames();
     virtual bool getIDBDatabaseMetaData(const String& name, IDBDatabaseMetadata*, bool& success) WARN_UNUSED_RETURN;
@@ -170,7 +171,7 @@
     };
 
 protected:
-    IDBBackingStore(const String& identifier, IDBFactoryBackendImpl*, PassOwnPtr<LevelDBDatabase>);
+    IDBBackingStore(const String& identifier, PassOwnPtr<LevelDBDatabase>);
 
     // Should only used for mocking.
     IDBBackingStore();
@@ -180,10 +181,10 @@
     void getIndexes(int64_t databaseId, int64_t objectStoreId, IDBObjectStoreMetadata::IndexMap*);
 
     String m_identifier;
-    RefPtr<IDBFactoryBackendImpl> m_factory;
+
     OwnPtr<LevelDBDatabase> m_db;
     OwnPtr<LevelDBComparator> m_comparator;
-
+    WeakPtrFactory<IDBBackingStore> m_weakFactory;
 };
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/Modules/indexeddb/IDBFactoryBackendImpl.cpp (145237 => 145238)


--- trunk/Source/WebCore/Modules/indexeddb/IDBFactoryBackendImpl.cpp	2013-03-08 17:42:13 UTC (rev 145237)
+++ trunk/Source/WebCore/Modules/indexeddb/IDBFactoryBackendImpl.cpp	2013-03-08 18:06:23 UTC (rev 145238)
@@ -41,6 +41,20 @@
 
 namespace WebCore {
 
+template<typename K, typename M>
+static void cleanWeakMap(HashMap<K, WeakPtr<M> >& map)
+{
+    HashMap<K, WeakPtr<M> > other;
+    other.swap(map);
+
+    typename HashMap<K, WeakPtr<M> >::const_iterator iter = other.begin();
+    while (iter != other.end()) {
+        if (iter->value.get())
+            map.set(iter->key, iter->value);
+        ++iter;
+    }
+}
+
 static String computeFileIdentifier(SecurityOrigin* securityOrigin)
 {
     static const char levelDBFileSuffix[] = "@1";
@@ -66,18 +80,6 @@
     m_databaseBackendMap.remove(uniqueIdentifier);
 }
 
-void IDBFactoryBackendImpl::addIDBBackingStore(const String& fileIdentifier, IDBBackingStore* backingStore)
-{
-    ASSERT(!m_backingStoreMap.contains(fileIdentifier));
-    m_backingStoreMap.set(fileIdentifier, backingStore);
-}
-
-void IDBFactoryBackendImpl::removeIDBBackingStore(const String& fileIdentifier)
-{
-    ASSERT(m_backingStoreMap.contains(fileIdentifier));
-    m_backingStoreMap.remove(fileIdentifier);
-}
-
 void IDBFactoryBackendImpl::getDatabaseNames(PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<SecurityOrigin> securityOrigin, ScriptExecutionContext*, const String& dataDirectory)
 {
     RefPtr<IDBBackingStore> backingStore = openBackingStore(securityOrigin, dataDirectory);
@@ -127,16 +129,18 @@
 {
     const String fileIdentifier = computeFileIdentifier(securityOrigin.get());
 
-    RefPtr<IDBBackingStore> backingStore;
     IDBBackingStoreMap::iterator it2 = m_backingStoreMap.find(fileIdentifier);
-    if (it2 != m_backingStoreMap.end())
-        backingStore = it2->value;
-    else {
-        backingStore = IDBBackingStore::open(securityOrigin.get(), dataDirectory, fileIdentifier, this);
+    if (it2 != m_backingStoreMap.end()) {
+        if (it2->value.get())
+            return it2->value.get();
     }
 
-    if (backingStore)
+    RefPtr<IDBBackingStore> backingStore = IDBBackingStore::open(securityOrigin.get(), dataDirectory, fileIdentifier);
+    if (backingStore) {
+        cleanWeakMap(m_backingStoreMap);
+        m_backingStoreMap.set(fileIdentifier, backingStore->createWeakPtr());
         return backingStore.release();
+    }
 
     return 0;
 }

Modified: trunk/Source/WebCore/Modules/indexeddb/IDBFactoryBackendImpl.h (145237 => 145238)


--- trunk/Source/WebCore/Modules/indexeddb/IDBFactoryBackendImpl.h	2013-03-08 17:42:13 UTC (rev 145237)
+++ trunk/Source/WebCore/Modules/indexeddb/IDBFactoryBackendImpl.h	2013-03-08 18:06:23 UTC (rev 145238)
@@ -33,6 +33,8 @@
 #include "IDBFactoryBackendInterface.h"
 #include "SecurityOrigin.h"
 #include <wtf/HashMap.h>
+#include <wtf/RefCounted.h>
+#include <wtf/WeakPtr.h>
 #include <wtf/text/StringHash.h>
 
 #if ENABLE(INDEXED_DATABASE)
@@ -54,8 +56,6 @@
 
     // Notifications from weak pointers.
     virtual void removeIDBDatabaseBackend(const String& uniqueIdentifier);
-    void addIDBBackingStore(const String& fileIdentifier, IDBBackingStore*);
-    virtual void removeIDBBackingStore(const String& fileIdentifier);
 
     virtual void getDatabaseNames(PassRefPtr<IDBCallbacks>, PassRefPtr<SecurityOrigin>, ScriptExecutionContext*, const String& dataDir);
     virtual void open(const String& name, int64_t version, int64_t transactionId, PassRefPtr<IDBCallbacks>, PassRefPtr<IDBDatabaseCallbacks>, PassRefPtr<SecurityOrigin>, ScriptExecutionContext*, const String& dataDir);
@@ -70,7 +70,7 @@
     typedef HashMap<String, RefPtr<IDBDatabaseBackendImpl> > IDBDatabaseBackendMap;
     IDBDatabaseBackendMap m_databaseBackendMap;
 
-    typedef HashMap<String, IDBBackingStore*> IDBBackingStoreMap;
+    typedef HashMap<String, WeakPtr<IDBBackingStore> > IDBBackingStoreMap;
     IDBBackingStoreMap m_backingStoreMap;
 
     // Only one instance of the factory should exist at any given time.

Modified: trunk/Source/WebKit/chromium/ChangeLog (145237 => 145238)


--- trunk/Source/WebKit/chromium/ChangeLog	2013-03-08 17:42:13 UTC (rev 145237)
+++ trunk/Source/WebKit/chromium/ChangeLog	2013-03-08 18:06:23 UTC (rev 145238)
@@ -1,3 +1,20 @@
+2013-03-08  Joshua Bell  <jsb...@chromium.org>
+
+        IndexedDB: Use WeakPtr for Factory-to-BackingStore reference
+        https://bugs.webkit.org/show_bug.cgi?id=111459
+
+        Reviewed by Adam Barth.
+
+        Add new test that verifies refcounts.
+
+        * WebKit.gyp: Don't include files depending on webkit_support.
+        * tests/IDBBackingStoreTest.cpp:
+        (WebCore::IDBBackingStoreTest::SetUp): No need for dummy factory.
+        (MockIDBFactoryBackend): Allow access to protected openBackingStore method.
+        (WebCore::TEST): Add new test that verifies refcounts.
+        * tests/IDBCleanupOnIOErrorTest.cpp:
+        (WebCore::TEST): No need for dummy factory.
+
 2013-03-07  Keishi Hattori  <kei...@webkit.org>
 
         Update calendar picker UI

Modified: trunk/Source/WebKit/chromium/WebKit.gyp (145237 => 145238)


--- trunk/Source/WebKit/chromium/WebKit.gyp	2013-03-08 17:42:13 UTC (rev 145237)
+++ trunk/Source/WebKit/chromium/WebKit.gyp	2013-03-08 18:06:23 UTC (rev 145238)
@@ -653,6 +653,7 @@
                                 # We should not include files depending on webkit_support.
                                 # These tests depend on webkit_support and
                                 # functions defined only in !WEBKIT_IMPLEMENTATION.
+                                'tests/IDBBackingStoreTest.cpp',
                                 'tests/IDBCleanupOnIOErrorTest.cpp',
                                 'tests/LevelDBTest.cpp',
                             ],

Modified: trunk/Source/WebKit/chromium/tests/IDBBackingStoreTest.cpp (145237 => 145238)


--- trunk/Source/WebKit/chromium/tests/IDBBackingStoreTest.cpp	2013-03-08 17:42:13 UTC (rev 145237)
+++ trunk/Source/WebKit/chromium/tests/IDBBackingStoreTest.cpp	2013-03-08 18:06:23 UTC (rev 145238)
@@ -27,9 +27,11 @@
 
 #include "IDBBackingStore.h"
 
+#include "IDBFactoryBackendImpl.h"
 #include "SharedBuffer.h"
 
 #include <gtest/gtest.h>
+#include <webkit/support/webkit_support.h>
 
 #if ENABLE(INDEXED_DATABASE)
 
@@ -43,11 +45,10 @@
     void SetUp()
     {
         SecurityOrigin* securityOrigin = 0;
-        m_factory = 0;
         // Empty pathBase means an in-memory database.
         String pathBase;
         String fileIdentifier;
-        m_backingStore = IDBBackingStore::open(securityOrigin, pathBase, fileIdentifier, m_factory);
+        m_backingStore = IDBBackingStore::open(securityOrigin, pathBase, fileIdentifier);
 
         // useful keys and values during tests
         const char rawValue1[] = "value1";
@@ -59,7 +60,6 @@
     }
 
 protected:
-    IDBFactoryBackendImpl* m_factory;
     RefPtr<IDBBackingStore> m_backingStore;
 
     // Sample keys and values that are consistent.
@@ -183,6 +183,42 @@
     }
 }
 
+class MockIDBFactoryBackend : public IDBFactoryBackendImpl {
+public:
+    static PassRefPtr<MockIDBFactoryBackend> create()
+    {
+        return adoptRef(new MockIDBFactoryBackend());
+    }
+
+    PassRefPtr<IDBBackingStore> testOpenBackingStore(PassRefPtr<SecurityOrigin> origin, const String& dataDirectory)
+    {
+        return openBackingStore(origin, dataDirectory);
+    }
+};
+
+TEST(IDBFactoryBackendTest, BackingStoreLifetime)
+{
+    RefPtr<SecurityOrigin> origin1 = SecurityOrigin::create("http", "localhost", 81);
+    RefPtr<SecurityOrigin> origin2 = SecurityOrigin::create("http", "localhost", 82);
+
+    RefPtr<MockIDBFactoryBackend> factory = MockIDBFactoryBackend::create();
+
+    OwnPtr<webkit_support::ScopedTempDirectory> tempDirectory = adoptPtr(webkit_support::CreateScopedTempDirectory());
+    tempDirectory->CreateUniqueTempDir();
+    const String path = String::fromUTF8(tempDirectory->path().c_str());
+
+    RefPtr<IDBBackingStore> diskStore1 = factory->testOpenBackingStore(origin1, path);
+    EXPECT_TRUE(diskStore1->hasOneRef());
+
+    RefPtr<IDBBackingStore> diskStore2 = factory->testOpenBackingStore(origin1, path);
+    EXPECT_EQ(diskStore2.get(), diskStore1.get());
+    EXPECT_EQ(diskStore2->refCount(), 2);
+
+    RefPtr<IDBBackingStore> diskStore3 = factory->testOpenBackingStore(origin2, path);
+    EXPECT_TRUE(diskStore3->hasOneRef());
+    EXPECT_EQ(diskStore1->refCount(), 2);
+}
+
 } // namespace
 
 #endif // ENABLE(INDEXED_DATABASE)

Modified: trunk/Source/WebKit/chromium/tests/IDBCleanupOnIOErrorTest.cpp (145237 => 145238)


--- trunk/Source/WebKit/chromium/tests/IDBCleanupOnIOErrorTest.cpp	2013-03-08 17:42:13 UTC (rev 145237)
+++ trunk/Source/WebKit/chromium/tests/IDBCleanupOnIOErrorTest.cpp	2013-03-08 18:06:23 UTC (rev 145238)
@@ -77,9 +77,8 @@
     tempDirectory->CreateUniqueTempDir();
     const String path = String::fromUTF8(tempDirectory->path().c_str());
     String dummyFileIdentifier;
-    IDBFactoryBackendImpl* dummyIDBFactory = 0;
     MockLevelDBFactory mockLevelDBFactory;
-    RefPtr<IDBBackingStore> backingStore = IDBBackingStore::open(origin.get(), path, dummyFileIdentifier, dummyIDBFactory, &mockLevelDBFactory);
+    RefPtr<IDBBackingStore> backingStore = IDBBackingStore::open(origin.get(), path, dummyFileIdentifier, &mockLevelDBFactory);
 }
 
 } // namespace
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to