Loaders: Add cancelation to all file loaders.
Mainly, for HTTP which might be stalled trying to connect (especially if you're not near your PC right now and it's in your recent, for example.)
This commit is contained in:
parent
6e3cb0cd48
commit
ee5b68f1fc
11 changed files with 87 additions and 43 deletions
|
@ -25,7 +25,7 @@
|
||||||
|
|
||||||
// Takes ownership of backend.
|
// Takes ownership of backend.
|
||||||
CachingFileLoader::CachingFileLoader(FileLoader *backend)
|
CachingFileLoader::CachingFileLoader(FileLoader *backend)
|
||||||
: filesize_(0), backend_(backend), exists_(-1), isDirectory_(-1), aheadThread_(false) {
|
: backend_(backend) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void CachingFileLoader::Prepare() {
|
void CachingFileLoader::Prepare() {
|
||||||
|
@ -288,3 +288,7 @@ void CachingFileLoader::StartReadAhead(s64 pos) {
|
||||||
});
|
});
|
||||||
th.detach();
|
th.detach();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CachingFileLoader::Cancel() {
|
||||||
|
backend_->Cancel();
|
||||||
|
}
|
||||||
|
|
|
@ -39,6 +39,8 @@ public:
|
||||||
}
|
}
|
||||||
size_t ReadAt(s64 absolutePos, size_t bytes, void *data, Flags flags = Flags::NONE) override;
|
size_t ReadAt(s64 absolutePos, size_t bytes, void *data, Flags flags = Flags::NONE) override;
|
||||||
|
|
||||||
|
void Cancel() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void Prepare();
|
void Prepare();
|
||||||
void InitCache();
|
void InitCache();
|
||||||
|
@ -57,10 +59,10 @@ private:
|
||||||
BLOCK_READAHEAD = 4,
|
BLOCK_READAHEAD = 4,
|
||||||
};
|
};
|
||||||
|
|
||||||
s64 filesize_;
|
s64 filesize_ = 0;
|
||||||
FileLoader *backend_;
|
FileLoader *backend_;
|
||||||
int exists_;
|
int exists_ = -1;
|
||||||
int isDirectory_;
|
int isDirectory_ = -1;
|
||||||
u64 generation_;
|
u64 generation_;
|
||||||
u64 oldestGeneration_;
|
u64 oldestGeneration_;
|
||||||
size_t cacheSize_;
|
size_t cacheSize_;
|
||||||
|
@ -77,6 +79,6 @@ private:
|
||||||
|
|
||||||
std::map<s64, BlockInfo> blocks_;
|
std::map<s64, BlockInfo> blocks_;
|
||||||
std::recursive_mutex blocksMutex_;
|
std::recursive_mutex blocksMutex_;
|
||||||
bool aheadThread_;
|
bool aheadThread_ = false;
|
||||||
std::once_flag preparedFlag_;
|
std::once_flag preparedFlag_;
|
||||||
};
|
};
|
||||||
|
|
|
@ -41,19 +41,16 @@ std::mutex DiskCachingFileLoader::cachesMutex_;
|
||||||
|
|
||||||
// Takes ownership of backend.
|
// Takes ownership of backend.
|
||||||
DiskCachingFileLoader::DiskCachingFileLoader(FileLoader *backend)
|
DiskCachingFileLoader::DiskCachingFileLoader(FileLoader *backend)
|
||||||
: prepared_(false), filesize_(0), backend_(backend), cache_(nullptr) {
|
: backend_(backend) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DiskCachingFileLoader::Prepare() {
|
void DiskCachingFileLoader::Prepare() {
|
||||||
if (prepared_) {
|
std::call_once(preparedFlag_, [this]() {
|
||||||
return;
|
|
||||||
}
|
|
||||||
prepared_ = true;
|
|
||||||
|
|
||||||
filesize_ = backend_->FileSize();
|
filesize_ = backend_->FileSize();
|
||||||
if (filesize_ > 0) {
|
if (filesize_ > 0) {
|
||||||
InitCache();
|
InitCache();
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
DiskCachingFileLoader::~DiskCachingFileLoader() {
|
DiskCachingFileLoader::~DiskCachingFileLoader() {
|
||||||
|
@ -118,6 +115,10 @@ size_t DiskCachingFileLoader::ReadAt(s64 absolutePos, size_t bytes, void *data,
|
||||||
return readSize;
|
return readSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DiskCachingFileLoader::Cancel() {
|
||||||
|
backend_->Cancel();
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<std::string> DiskCachingFileLoader::GetCachedPathsInUse() {
|
std::vector<std::string> DiskCachingFileLoader::GetCachedPathsInUse() {
|
||||||
std::lock_guard<std::mutex> guard(cachesMutex_);
|
std::lock_guard<std::mutex> guard(cachesMutex_);
|
||||||
|
|
||||||
|
@ -156,7 +157,7 @@ void DiskCachingFileLoader::ShutdownCache() {
|
||||||
}
|
}
|
||||||
|
|
||||||
DiskCachingFileLoaderCache::DiskCachingFileLoaderCache(const std::string &path, u64 filesize)
|
DiskCachingFileLoaderCache::DiskCachingFileLoaderCache(const std::string &path, u64 filesize)
|
||||||
: refCount_(0), filesize_(filesize), origPath_(path), f_(nullptr), fd_(0) {
|
: filesize_(filesize), origPath_(path) {
|
||||||
InitCache(path);
|
InitCache(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,6 +43,8 @@ public:
|
||||||
}
|
}
|
||||||
size_t ReadAt(s64 absolutePos, size_t bytes, void *data, Flags flags = Flags::NONE) override;
|
size_t ReadAt(s64 absolutePos, size_t bytes, void *data, Flags flags = Flags::NONE) override;
|
||||||
|
|
||||||
|
void Cancel() override;
|
||||||
|
|
||||||
static std::vector<std::string> GetCachedPathsInUse();
|
static std::vector<std::string> GetCachedPathsInUse();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -50,10 +52,10 @@ private:
|
||||||
void InitCache();
|
void InitCache();
|
||||||
void ShutdownCache();
|
void ShutdownCache();
|
||||||
|
|
||||||
bool prepared_;
|
std::once_flag preparedFlag_;
|
||||||
s64 filesize_;
|
s64 filesize_ = 0;
|
||||||
FileLoader *backend_;
|
FileLoader *backend_;
|
||||||
DiskCachingFileLoaderCache *cache_;
|
DiskCachingFileLoaderCache *cache_ = nullptr;
|
||||||
|
|
||||||
// We don't support concurrent disk cache access (we use memory cached indexes.)
|
// We don't support concurrent disk cache access (we use memory cached indexes.)
|
||||||
// So we have to ensure there's only one of these per.
|
// So we have to ensure there's only one of these per.
|
||||||
|
@ -139,7 +141,7 @@ private:
|
||||||
INVALID_INDEX = 0xFFFFFFFF,
|
INVALID_INDEX = 0xFFFFFFFF,
|
||||||
};
|
};
|
||||||
|
|
||||||
int refCount_;
|
int refCount_ = 0;
|
||||||
s64 filesize_;
|
s64 filesize_;
|
||||||
u32 blockSize_;
|
u32 blockSize_;
|
||||||
u16 generation_;
|
u16 generation_;
|
||||||
|
@ -176,8 +178,8 @@ private:
|
||||||
std::vector<BlockInfo> index_;
|
std::vector<BlockInfo> index_;
|
||||||
std::vector<u32> blockIndexLookup_;
|
std::vector<u32> blockIndexLookup_;
|
||||||
|
|
||||||
FILE *f_;
|
FILE *f_ = nullptr;
|
||||||
int fd_;
|
int fd_ = 0;
|
||||||
|
|
||||||
static std::string cacheDir_;
|
static std::string cacheDir_;
|
||||||
};
|
};
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
#include "Core/FileLoaders/HTTPFileLoader.h"
|
#include "Core/FileLoaders/HTTPFileLoader.h"
|
||||||
|
|
||||||
HTTPFileLoader::HTTPFileLoader(const std::string &filename)
|
HTTPFileLoader::HTTPFileLoader(const std::string &filename)
|
||||||
: filesize_(0), filepos_(0), url_(filename), filename_(filename), connected_(false) {
|
: url_(filename), filename_(filename) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void HTTPFileLoader::Prepare() {
|
void HTTPFileLoader::Prepare() {
|
||||||
|
@ -33,6 +33,10 @@ void HTTPFileLoader::Prepare() {
|
||||||
}
|
}
|
||||||
|
|
||||||
Connect();
|
Connect();
|
||||||
|
if (!connected_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
int err = client_.SendRequest("HEAD", url_.Resource().c_str());
|
int err = client_.SendRequest("HEAD", url_.Resource().c_str());
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
Disconnect();
|
Disconnect();
|
||||||
|
@ -123,6 +127,9 @@ size_t HTTPFileLoader::ReadAt(s64 absolutePos, size_t bytes, void *data, Flags f
|
||||||
}
|
}
|
||||||
|
|
||||||
Connect();
|
Connect();
|
||||||
|
if (!connected_) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
char requestHeaders[4096];
|
char requestHeaders[4096];
|
||||||
// Note that the Range header is *inclusive*.
|
// Note that the Range header is *inclusive*.
|
||||||
|
@ -186,3 +193,11 @@ size_t HTTPFileLoader::ReadAt(s64 absolutePos, size_t bytes, void *data, Flags f
|
||||||
filepos_ = absolutePos + readBytes;
|
filepos_ = absolutePos + readBytes;
|
||||||
return readBytes;
|
return readBytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HTTPFileLoader::Connect() {
|
||||||
|
if (!connected_) {
|
||||||
|
cancelConnect_ = false;
|
||||||
|
// Latency is important here, so reduce the timeout.
|
||||||
|
connected_ = client_.Connect(3, 10.0, &cancelConnect_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -41,14 +41,14 @@ public:
|
||||||
}
|
}
|
||||||
virtual size_t ReadAt(s64 absolutePos, size_t bytes, void *data, Flags flags = Flags::NONE) override;
|
virtual size_t ReadAt(s64 absolutePos, size_t bytes, void *data, Flags flags = Flags::NONE) override;
|
||||||
|
|
||||||
|
void Cancel() override {
|
||||||
|
cancelConnect_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void Prepare();
|
void Prepare();
|
||||||
|
|
||||||
void Connect() {
|
void Connect();
|
||||||
if (!connected_) {
|
|
||||||
connected_ = client_.Connect();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Disconnect() {
|
void Disconnect() {
|
||||||
if (connected_) {
|
if (connected_) {
|
||||||
|
@ -57,12 +57,13 @@ private:
|
||||||
connected_ = false;
|
connected_ = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
s64 filesize_;
|
s64 filesize_ = 0;
|
||||||
s64 filepos_;
|
s64 filepos_ = 0;
|
||||||
Url url_;
|
Url url_;
|
||||||
http::Client client_;
|
http::Client client_;
|
||||||
std::string filename_;
|
std::string filename_;
|
||||||
bool connected_;
|
bool connected_ = false;
|
||||||
|
bool cancelConnect_ = false;
|
||||||
|
|
||||||
std::once_flag preparedFlag_;
|
std::once_flag preparedFlag_;
|
||||||
std::mutex readAtMutex_;
|
std::mutex readAtMutex_;
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
|
|
||||||
// Takes ownership of backend.
|
// Takes ownership of backend.
|
||||||
RamCachingFileLoader::RamCachingFileLoader(FileLoader *backend)
|
RamCachingFileLoader::RamCachingFileLoader(FileLoader *backend)
|
||||||
: filesize_(0), backend_(backend), exists_(-1), isDirectory_(-1), aheadThread_(false) {
|
: backend_(backend) {
|
||||||
filesize_ = backend->FileSize();
|
filesize_ = backend->FileSize();
|
||||||
if (filesize_ > 0) {
|
if (filesize_ > 0) {
|
||||||
InitCache();
|
InitCache();
|
||||||
|
@ -107,11 +107,7 @@ void RamCachingFileLoader::InitCache() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void RamCachingFileLoader::ShutdownCache() {
|
void RamCachingFileLoader::ShutdownCache() {
|
||||||
{
|
Cancel();
|
||||||
std::lock_guard<std::mutex> guard(blocksMutex_);
|
|
||||||
// Try to have the thread stop.
|
|
||||||
aheadRemaining_ = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We can't delete while the thread is running, so have to wait.
|
// We can't delete while the thread is running, so have to wait.
|
||||||
// This should only happen from the menu.
|
// This should only happen from the menu.
|
||||||
|
@ -127,6 +123,15 @@ void RamCachingFileLoader::ShutdownCache() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RamCachingFileLoader::Cancel() {
|
||||||
|
if (aheadThread_) {
|
||||||
|
std::lock_guard<std::mutex> guard(blocksMutex_);
|
||||||
|
aheadCancel_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
backend_->Cancel();
|
||||||
|
}
|
||||||
|
|
||||||
size_t RamCachingFileLoader::ReadFromCache(s64 pos, size_t bytes, void *data) {
|
size_t RamCachingFileLoader::ReadFromCache(s64 pos, size_t bytes, void *data) {
|
||||||
s64 cacheStartPos = pos >> BLOCK_SHIFT;
|
s64 cacheStartPos = pos >> BLOCK_SHIFT;
|
||||||
s64 cacheEndPos = (pos + bytes - 1) >> BLOCK_SHIFT;
|
s64 cacheEndPos = (pos + bytes - 1) >> BLOCK_SHIFT;
|
||||||
|
@ -220,10 +225,11 @@ void RamCachingFileLoader::StartReadAhead(s64 pos) {
|
||||||
}
|
}
|
||||||
|
|
||||||
aheadThread_ = true;
|
aheadThread_ = true;
|
||||||
|
aheadCancel_ = false;
|
||||||
std::thread th([this] {
|
std::thread th([this] {
|
||||||
setCurrentThreadName("FileLoaderReadAhead");
|
setCurrentThreadName("FileLoaderReadAhead");
|
||||||
|
|
||||||
while (aheadRemaining_ != 0) {
|
while (aheadRemaining_ != 0 && !aheadCancel_) {
|
||||||
// Where should we look?
|
// Where should we look?
|
||||||
const u32 cacheStartPos = NextAheadBlock();
|
const u32 cacheStartPos = NextAheadBlock();
|
||||||
if (cacheStartPos == 0xFFFFFFFF) {
|
if (cacheStartPos == 0xFFFFFFFF) {
|
||||||
|
|
|
@ -39,6 +39,8 @@ public:
|
||||||
}
|
}
|
||||||
size_t ReadAt(s64 absolutePos, size_t bytes, void *data, Flags flags = Flags::NONE) override;
|
size_t ReadAt(s64 absolutePos, size_t bytes, void *data, Flags flags = Flags::NONE) override;
|
||||||
|
|
||||||
|
void Cancel() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void InitCache();
|
void InitCache();
|
||||||
void ShutdownCache();
|
void ShutdownCache();
|
||||||
|
@ -55,15 +57,16 @@ private:
|
||||||
BLOCK_READAHEAD = 4,
|
BLOCK_READAHEAD = 4,
|
||||||
};
|
};
|
||||||
|
|
||||||
s64 filesize_;
|
s64 filesize_ = 0;
|
||||||
FileLoader *backend_;
|
FileLoader *backend_;
|
||||||
u8 *cache_;
|
u8 *cache_ = nullptr;
|
||||||
int exists_;
|
int exists_ = -1;
|
||||||
int isDirectory_;
|
int isDirectory_ = -1;
|
||||||
|
|
||||||
std::vector<u8> blocks_;
|
std::vector<u8> blocks_;
|
||||||
std::mutex blocksMutex_;
|
std::mutex blocksMutex_;
|
||||||
u32 aheadRemaining_;
|
u32 aheadRemaining_;
|
||||||
s64 aheadPos_;
|
s64 aheadPos_;
|
||||||
bool aheadThread_;
|
bool aheadThread_ = false;
|
||||||
|
bool aheadCancel_ = false;
|
||||||
};
|
};
|
||||||
|
|
|
@ -72,3 +72,7 @@ size_t RetryingFileLoader::ReadAt(s64 absolutePos, size_t bytes, void *data, Fla
|
||||||
|
|
||||||
return readSize;
|
return readSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RetryingFileLoader::Cancel() {
|
||||||
|
backend_->Cancel();
|
||||||
|
}
|
||||||
|
|
|
@ -36,6 +36,8 @@ public:
|
||||||
}
|
}
|
||||||
size_t ReadAt(s64 absolutePos, size_t bytes, void *data, Flags flags = Flags::NONE) override;
|
size_t ReadAt(s64 absolutePos, size_t bytes, void *data, Flags flags = Flags::NONE) override;
|
||||||
|
|
||||||
|
void Cancel() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum {
|
enum {
|
||||||
MAX_RETRIES = 3,
|
MAX_RETRIES = 3,
|
||||||
|
|
|
@ -86,6 +86,10 @@ public:
|
||||||
virtual size_t ReadAt(s64 absolutePos, size_t bytes, void *data, Flags flags = Flags::NONE) {
|
virtual size_t ReadAt(s64 absolutePos, size_t bytes, void *data, Flags flags = Flags::NONE) {
|
||||||
return ReadAt(absolutePos, 1, bytes, data, flags);
|
return ReadAt(absolutePos, 1, bytes, data, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Cancel any operations that might block, if possible.
|
||||||
|
virtual void Cancel() {
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
inline u32 operator & (const FileLoader::Flags &a, const FileLoader::Flags &b) {
|
inline u32 operator & (const FileLoader::Flags &a, const FileLoader::Flags &b) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue