CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
hrydgard

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: hrydgard/ppsspp
Path: blob/master/Core/FileLoaders/DiskCachingFileLoader.h
Views: 1401
1
// Copyright (c) 2012- PPSSPP Project.
2
3
// This program is free software: you can redistribute it and/or modify
4
// it under the terms of the GNU General Public License as published by
5
// the Free Software Foundation, version 2.0 or later versions.
6
7
// This program is distributed in the hope that it will be useful,
8
// but WITHOUT ANY WARRANTY; without even the implied warranty of
9
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
// GNU General Public License 2.0 for more details.
11
12
// A copy of the GPL 2.0 should have been included with the program.
13
// If not, see http://www.gnu.org/licenses/
14
15
// Official git repository and contact information can be found at
16
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
17
18
#pragma once
19
20
#include <vector>
21
#include <map>
22
#include <mutex>
23
24
#include "Common/CommonTypes.h"
25
#include "Common/File/Path.h"
26
#include "Common/Swap.h"
27
#include "Core/Loaders.h"
28
29
class DiskCachingFileLoaderCache;
30
31
class DiskCachingFileLoader : public ProxiedFileLoader {
32
public:
33
DiskCachingFileLoader(FileLoader *backend);
34
~DiskCachingFileLoader();
35
36
bool Exists() override;
37
bool ExistsFast() override;
38
s64 FileSize() override;
39
40
size_t ReadAt(s64 absolutePos, size_t bytes, size_t count, void *data, Flags flags = Flags::NONE) override {
41
return ReadAt(absolutePos, bytes * count, data, flags) / bytes;
42
}
43
size_t ReadAt(s64 absolutePos, size_t bytes, void *data, Flags flags = Flags::NONE) override;
44
45
static std::vector<Path> GetCachedPathsInUse();
46
47
private:
48
void Prepare();
49
void InitCache();
50
void ShutdownCache();
51
52
std::once_flag preparedFlag_;
53
s64 filesize_ = 0;
54
DiskCachingFileLoaderCache *cache_ = nullptr;
55
56
// We don't support concurrent disk cache access (we use memory cached indexes.)
57
// So we have to ensure there's only one of these per.
58
static std::map<Path, DiskCachingFileLoaderCache *> caches_;
59
static std::mutex cachesMutex_;
60
};
61
62
class DiskCachingFileLoaderCache {
63
public:
64
DiskCachingFileLoaderCache(const Path &path, u64 filesize);
65
~DiskCachingFileLoaderCache();
66
67
bool IsValid() {
68
return f_ != nullptr;
69
}
70
71
void AddRef() {
72
++refCount_;
73
}
74
75
bool Release() {
76
return --refCount_ == 0;
77
}
78
79
static void SetCacheDir(const Path &path) {
80
cacheDir_ = path;
81
}
82
83
size_t ReadFromCache(s64 pos, size_t bytes, void *data);
84
// Guaranteed to read at least one block into the cache.
85
size_t SaveIntoCache(FileLoader *backend, s64 pos, size_t bytes, void *data, FileLoader::Flags flags);
86
87
bool HasData() const;
88
89
private:
90
void InitCache(const Path &path);
91
void ShutdownCache();
92
bool MakeCacheSpaceFor(size_t blocks);
93
void RebalanceGenerations();
94
u32 AllocateBlock(u32 indexPos);
95
96
struct BlockInfo;
97
bool ReadBlockData(u8 *dest, BlockInfo &info, size_t offset, size_t size);
98
void WriteBlockData(BlockInfo &info, const u8 *src);
99
void WriteIndexData(u32 indexPos, BlockInfo &info);
100
s64 GetBlockOffset(u32 block);
101
102
Path MakeCacheFilePath(const Path &filename);
103
std::string MakeCacheFilename(const Path &path);
104
bool LoadCacheFile(const Path &path);
105
void LoadCacheIndex();
106
void CreateCacheFile(const Path &path);
107
bool LockCacheFile(bool lockStatus);
108
bool RemoveCacheFile(const Path &path);
109
void CloseFileHandle();
110
111
u64 FreeDiskSpace();
112
u32 DetermineMaxBlocks();
113
u32 CountCachedFiles();
114
void GarbageCollectCacheFiles(u64 goalBytes);
115
116
// File format:
117
// 64 magic
118
// 32 version
119
// 32 blockSize
120
// 64 filesize
121
// 32 maxBlocks
122
// 32 flags
123
// index[filesize / blockSize] <-- ~500 KB for 4GB
124
// 32 (fileoffset - headersize) / blockSize -> -1=not present
125
// 16 generation?
126
// 16 hits?
127
// blocks[up to maxBlocks]
128
// 8 * blockSize
129
130
enum {
131
CACHE_VERSION = 3,
132
DEFAULT_BLOCK_SIZE = 65536,
133
MAX_BLOCKS_PER_READ = 16,
134
MAX_BLOCKS_LOWER_BOUND = 256, // 16 MB
135
MAX_BLOCKS_UPPER_BOUND = 8192, // 512 MB
136
INVALID_BLOCK = 0xFFFFFFFF,
137
INVALID_INDEX = 0xFFFFFFFF,
138
};
139
140
int refCount_ = 0;
141
s64 filesize_;
142
u32 blockSize_;
143
u16 generation_;
144
u16 oldestGeneration_;
145
u32 maxBlocks_;
146
u32 flags_;
147
size_t cacheSize_;
148
size_t indexCount_;
149
std::mutex lock_;
150
Path origPath_;
151
152
struct FileHeader {
153
char magic[8];
154
u32_le version;
155
u32_le blockSize;
156
s64_le filesize;
157
u32_le maxBlocks;
158
u32_le flags;
159
};
160
161
enum FileFlags {
162
FLAG_LOCKED = 1 << 0,
163
};
164
165
struct BlockInfo {
166
u32 block;
167
u16 generation;
168
u16 hits;
169
170
BlockInfo() : block(-1), generation(0), hits(0) {
171
}
172
};
173
174
std::vector<BlockInfo> index_;
175
std::vector<u32> blockIndexLookup_;
176
177
FILE *f_ = nullptr;
178
int fd_ = 0;
179
180
static Path cacheDir_;
181
};
182
183