mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-12-08 06:09:58 +00:00
We previously had no protection against the same URL being requested
multiple times at the same time. For example, if a URL did not have any
cache entry and became requested twice, we would open two cache writers
concurrently. This would result in both writers piping the response to
disk, and we'd have a corrupt cache file.
We now hold back requests under certain scenarios until existing cache
entries have completed:
* If we are opening a cache entry for reading:
- If there is an existing reader entry, carry on as normal. We can
have multiple readers.
- If there is an existing writer entry, defer the request until it is
complete.
* If we are opening a cache entry for writing:
- If there is an existing reader or writer entry, defer the request
until it is complete.
54 lines
1.4 KiB
C++
54 lines
1.4 KiB
C++
/*
|
|
* Copyright (c) 2025, Tim Flynn <trflynn89@ladybird.org>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <AK/Error.h>
|
|
#include <AK/LexicalPath.h>
|
|
#include <AK/Optional.h>
|
|
#include <AK/StringView.h>
|
|
#include <AK/Time.h>
|
|
#include <AK/Types.h>
|
|
#include <LibDatabase/Database.h>
|
|
#include <LibURL/Forward.h>
|
|
#include <RequestServer/Cache/CacheEntry.h>
|
|
#include <RequestServer/Cache/CacheIndex.h>
|
|
|
|
namespace RequestServer {
|
|
|
|
class DiskCache {
|
|
public:
|
|
static ErrorOr<DiskCache> create();
|
|
|
|
struct CacheHasOpenEntry { };
|
|
Variant<Optional<CacheEntryWriter&>, CacheHasOpenEntry> create_entry(Request&);
|
|
Variant<Optional<CacheEntryReader&>, CacheHasOpenEntry> open_entry(Request&);
|
|
|
|
void clear_cache();
|
|
|
|
LexicalPath const& cache_directory() { return m_cache_directory; }
|
|
|
|
void cache_entry_closed(Badge<CacheEntry>, CacheEntry const&);
|
|
|
|
private:
|
|
DiskCache(NonnullRefPtr<Database::Database>, LexicalPath cache_directory, CacheIndex);
|
|
|
|
enum class CheckReaderEntries {
|
|
No,
|
|
Yes,
|
|
};
|
|
bool check_if_cache_has_open_entry(Request&, u64 cache_key, CheckReaderEntries);
|
|
|
|
NonnullRefPtr<Database::Database> m_database;
|
|
|
|
HashMap<u64, Vector<NonnullOwnPtr<CacheEntry>, 1>> m_open_cache_entries;
|
|
HashMap<u64, Vector<WeakPtr<Request>, 1>> m_requests_waiting_completion;
|
|
|
|
LexicalPath m_cache_directory;
|
|
CacheIndex m_index;
|
|
};
|
|
|
|
}
|