⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 278778 in webkit


Ignore:
Timestamp:
Jun 11, 2021, 1:34:28 PM (5 years ago)
Author:
Chris Dumez
Message:

Regression(r276653) We're going to disk more often for local storage operations
​https://bugs.webkit.org/show_bug.cgi?id=226832

Reviewed by Darin Adler.

We're going to disk more often for local storage operations since r276653 because we no
longer keep items in memory. This results in a slightly increased power usage on one of
our benchmarks. As a first step to improve this, I am reintroducing a cache of the items
in memory, as long as the values are not too large (1Kb limit). We still go to disk to
look up values that are larger than 1Kb to avoid regressing memory usage.

  • NetworkProcess/WebStorage/LocalStorageDatabase.cpp:

(WebKit::LocalStorageDatabase::openDatabase):
(WebKit::LocalStorageDatabase::items const):
(WebKit::LocalStorageDatabase::removeItem):
(WebKit::LocalStorageDatabase::item const):
(WebKit::LocalStorageDatabase::itemBypassingCache const):
(WebKit::LocalStorageDatabase::setItem):
(WebKit::LocalStorageDatabase::clear):
(WebKit::LocalStorageDatabase::close):
(WebKit::LocalStorageDatabase::databaseIsEmpty const):

  • NetworkProcess/WebStorage/LocalStorageDatabase.h:
Location:
trunk/Source/WebKit
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebKit/ChangeLog

    r278772 r278778  
     12021-06-11  Chris Dumez  <cdumez@apple.com>
     2
     3        Regression(r276653) We're going to disk more often for local storage operations
     4        https://bugs.webkit.org/show_bug.cgi?id=226832
     5
     6        Reviewed by Darin Adler.
     7
     8        We're going to disk more often for local storage operations since r276653 because we no
     9        longer keep items in memory. This results in a slightly increased power usage on one of
     10        our benchmarks. As a first step to improve this, I am reintroducing a cache of the items
     11        in memory, as long as the values are not too large (1Kb limit). We still go to disk to
     12        look up values that are larger than 1Kb to avoid regressing memory usage.
     13
     14        * NetworkProcess/WebStorage/LocalStorageDatabase.cpp:
     15        (WebKit::LocalStorageDatabase::openDatabase):
     16        (WebKit::LocalStorageDatabase::items const):
     17        (WebKit::LocalStorageDatabase::removeItem):
     18        (WebKit::LocalStorageDatabase::item const):
     19        (WebKit::LocalStorageDatabase::itemBypassingCache const):
     20        (WebKit::LocalStorageDatabase::setItem):
     21        (WebKit::LocalStorageDatabase::clear):
     22        (WebKit::LocalStorageDatabase::close):
     23        (WebKit::LocalStorageDatabase::databaseIsEmpty const):
     24        * NetworkProcess/WebStorage/LocalStorageDatabase.h:
     25
    1262021-06-11  Chris Dumez  <cdumez@apple.com>
    227
  • trunk/Source/WebKit/NetworkProcess/WebStorage/LocalStorageDatabase.cpp

    r278651 r278778  
    3939using namespace WebCore;
    4040
    41 static const ASCIILiteral getItemsQueryString { "SELECT key, value FROM ItemTable"_s };
     41constexpr auto getItemsQueryString { "SELECT key, value FROM ItemTable"_s };
     42constexpr unsigned maximumSizeForValuesKeptInMemory { 1024 }; // 1 KB
    4243
    4344Ref<LocalStorageDatabase> LocalStorageDatabase::create(String&& databasePath, unsigned quotaInBytes)
    … …  
    6263{
    6364    ASSERT(!RunLoop::isMain());
    64     if (!FileSystem::fileExists(m_databasePath) && shouldCreateDatabase == ShouldCreateDatabase::No)
    65         return true;
     65    if (!FileSystem::fileExists(m_databasePath)) {
     66        if (shouldCreateDatabase == ShouldCreateDatabase::No)
     67            return true;
     68        m_items = HashMap<String, String> { };
     69    }
    6670
    6771    if (m_databasePath.isEmpty()) {
    … …  
    141145        return { };
    142146
     147    HashMap<String, String> items;
     148    if (m_items) {
     149        items.reserveInitialCapacity(m_items->size());
     150        for (auto& entry : *m_items) {
     151            auto value = entry.value.isNull() ? itemBypassingCache(entry.key) : entry.value;
     152            items.add(entry.key, WTFMove(value));
     153        }
     154        return items;
     155    }
     156
    143157    auto query = scopedStatement(m_getItemsStatement, getItemsQueryString);
    144158    if (!query) {
    … …  
    147161    }
    148162
    149     HashMap<String, String> items;
     163    m_items = HashMap<String, String> { };
    150164    int result = query->step();
    151165    while (result == SQLITE_ROW) {
    152166        String key = query->columnText(0);
    153167        String value = query->columnBlobAsString(1);
    154         if (!key.isNull() && !value.isNull())
     168        if (!key.isNull() && !value.isNull()) {
     169            m_items->add(key, value.sizeInBytes() > maximumSizeForValuesKeptInMemory ? String() : value);
    155170            items.add(WTFMove(key), WTFMove(value));
     171        }
    156172        result = query->step();
    157173    }
    … …  
    185201        return;
    186202    }
     203
     204    if (m_items)
     205        m_items->remove(key);
    187206}
    188207
    … …  
    193212        return { };
    194213
     214    if (m_items) {
     215        // Use find() instead of get() since a null String is a valid value here.
     216        auto it = m_items->find(key);
     217        if (it == m_items->end())
     218            return { };
     219        if (!it->value.isNull())
     220            return it->value;
     221        // The value is too large and needs to be fetched from the database.
     222    }
     223    return itemBypassingCache(key);
     224}
     225
     226String LocalStorageDatabase::itemBypassingCache(const String& key) const
     227{
    195228    auto query = scopedStatement(m_getItemStatement, "SELECT value FROM ItemTable WHERE key=?"_s);
    196229    if (!query) {
    … …  
    232265        if (result == SQLITE_FULL)
    233266            quotaException = true;
    234     }
     267        return;
     268    }
     269
     270    if (m_items)
     271        m_items->set(key, value.sizeInBytes() > maximumSizeForValuesKeptInMemory ? String() : value);
    235272}
    236273
    … …  
    239276    ASSERT(!RunLoop::isMain());
    240277    if (!m_database.isOpen())
     278        return false;
     279
     280    if (m_items && m_items->isEmpty())
    241281        return false;
    242282
    … …  
    251291        LOG_ERROR("Failed to clear all items in the local storage database - %i", result);
    252292        return false;
     293    }
     294
     295    if (m_items) {
     296        m_items->clear();
     297        return true;
    253298    }
    254299
    … …  
    270315    m_getItemsStatement = nullptr;
    271316    m_deleteItemStatement = nullptr;
     317    m_items = std::nullopt;
    272318
    273319    if (m_database.isOpen())
    … …  
    283329    if (!m_database.isOpen())
    284330        return false;
     331
     332    if (m_items)
     333        return m_items->isEmpty();
    285334
    286335    auto query = m_database.prepareStatement("SELECT COUNT(*) FROM ItemTable"_s);
  • trunk/Source/WebKit/NetworkProcess/WebStorage/LocalStorageDatabase.h

    r278651 r278778  
    6363    bool databaseIsEmpty() const;
    6464
     65    String itemBypassingCache(const String& key) const;
     66
    6567    WebCore::SQLiteStatementAutoResetScope scopedStatement(std::unique_ptr<WebCore::SQLiteStatement>&, ASCIILiteral query) const;
    6668
    … …  
    6971    const unsigned m_quotaInBytes { 0 };
    7072    bool m_isClosed { false };
     73
     74    // Cached version of the items in memory.
     75    // If the value is too large to keep in memory, we store a null String.
     76    mutable std::optional<HashMap<String, String>> m_items;
    7177
    7278    mutable std::unique_ptr<WebCore::SQLiteStatement> m_clearStatement;
Note: See TracChangeset for help on using the changeset viewer.