1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
|
// 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 {
// 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 must be done from the main thread
// - 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:
class Metadata {
public:
int64_t start_offset() const { return start_offset_; }
size_t size() const { return size_; }
Metadata(Metadata&& other) = delete;
private:
Metadata(int64_t start_offset, size_t size)
: start_offset_(start_offset), size_(size) {}
Metadata(const Metadata& other) = default;
Metadata& operator=(const Metadata& other) = default;
int64_t start_offset_;
size_t size_;
friend class DiskDataAllocator;
};
// 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<Metadata> Write(const void* data, size_t size);
// Reads data. A read failure is fatal.
// Must be called from the main thread.
// 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 Metadata& metadata, void* data);
// Discards existing data pointed at by |metadata|.
void Discard(std::unique_ptr<Metadata> 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:
Metadata FindChunk(size_t size) EXCLUSIVE_LOCKS_REQUIRED(mutex_);
void ReleaseChunk(const Metadata& 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_
|