blob: 7b13a5562f3fd232d84bce2faf2b4a5741fd12e4 [file] [log] [blame]
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_DISK_DATA_ALLOCATOR_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_DISK_DATA_ALLOCATOR_H_
#include <map>
#include <memory>
#include "base/files/file.h"
#include "base/synchronization/lock.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "third_party/blink/public/mojom/disk_allocator.mojom-blink.h"
#include "third_party/blink/renderer/platform/platform_export.h"
#include "third_party/blink/renderer/platform/wtf/threading.h"
#include "third_party/blink/renderer/platform/wtf/threading_primitives.h"
namespace blink {
class DiskDataMetadata;
// Stores data onto a single file.
//
// The file is provided after construction. As a consequence, the allocator
// initially does not accept writes, that is |Write()| returns nullptr. It may
// also become not usable later, for instance if disk space is no longer
// available.
//
// Threading:
// - Reads and writes can be done from any thread.
// - public methods are thread-safe, and unless otherwise noted, can be called
// from any thread.
class PLATFORM_EXPORT DiskDataAllocator : public mojom::blink::DiskAllocator {
public:
// Must be called on the main thread.
void ProvideTemporaryFile(::base::File file) override;
// Whether writes may succeed. This is not a guarantee. However, when this
// returns false, writes will fail.
bool may_write() LOCKS_EXCLUDED(mutex_);
// Returns |nullptr| in case of error.
// Note that this performs a blocking disk write.
std::unique_ptr<DiskDataMetadata> Write(const void* data, size_t size);
// Reads data. A read failure is fatal.
// Caller must make sure that this is not called at the same time as
// |Discard()|.
// Can be called at any time before |Discard()| destroys |metadata|.
//
// |data| must point to an area large enough to fit a |metadata.size|-ed
// array. Note that this performs a blocking disk read.
void Read(const DiskDataMetadata& metadata, void* data);
// Discards existing data pointed at by |metadata|. Caller must make sure this
// is not called while the same file is being read.
void Discard(std::unique_ptr<DiskDataMetadata> metadata);
~DiskDataAllocator() override;
static DiskDataAllocator& Instance();
static void Bind(mojo::PendingReceiver<mojom::blink::DiskAllocator> receiver);
int64_t disk_footprint() {
MutexLocker locker(mutex_);
return file_tail_;
}
size_t free_chunks_size() {
MutexLocker locker(mutex_);
return free_chunks_size_;
}
protected:
// Protected methods for testing.
DiskDataAllocator();
void set_may_write_for_testing(bool may_write) LOCKS_EXCLUDED(mutex_);
private:
DiskDataMetadata FindChunk(size_t size) EXCLUSIVE_LOCKS_REQUIRED(mutex_);
void ReleaseChunk(const DiskDataMetadata& metadata)
EXCLUSIVE_LOCKS_REQUIRED(mutex_);
// Virtual for testing.
virtual int DoWrite(int64_t offset, const char* data, int size)
LOCKS_EXCLUDED(mutex_);
// CHECK()s that the read is successful.
virtual void DoRead(int64_t offset, char* data, int size);
mojo::Receiver<mojom::blink::DiskAllocator> receiver_{this};
base::File file_; // May be invalid.
protected: // For testing.
Mutex mutex_;
// Using a std::map because we rely on |{lower,upper}_bound()|.
std::map<int64_t, size_t> free_chunks_ GUARDED_BY(mutex_);
size_t free_chunks_size_ GUARDED_BY(mutex_);
private:
int64_t file_tail_ GUARDED_BY(mutex_);
// Whether writing is possible now. This can be true if:
// - |set_may_write_for_testing()| was called, or
// - |file_.IsValid()| and no write error occurred (which would set
// |may_write_| to false).
bool may_write_ GUARDED_BY(mutex_);
#if DCHECK_IS_ON()
std::map<int64_t, size_t> allocated_chunks_ GUARDED_BY(mutex_);
#endif
FRIEND_TEST_ALL_PREFIXES(DiskDataAllocatorTest, ProvideInvalidFile);
FRIEND_TEST_ALL_PREFIXES(DiskDataAllocatorTest, ProvideValidFile);
};
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_DISK_DATA_ALLOCATOR_H_