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:
Unknown W. Brackets 2017-12-09 16:47:37 -08:00
parent 6e3cb0cd48
commit ee5b68f1fc
11 changed files with 87 additions and 43 deletions

View File

@ -25,7 +25,7 @@
// Takes ownership of backend.
CachingFileLoader::CachingFileLoader(FileLoader *backend)
: filesize_(0), backend_(backend), exists_(-1), isDirectory_(-1), aheadThread_(false) {
: backend_(backend) {
}
void CachingFileLoader::Prepare() {
@ -288,3 +288,7 @@ void CachingFileLoader::StartReadAhead(s64 pos) {
});
th.detach();
}
void CachingFileLoader::Cancel() {
backend_->Cancel();
}

View File

@ -39,6 +39,8 @@ public:
}
size_t ReadAt(s64 absolutePos, size_t bytes, void *data, Flags flags = Flags::NONE) override;
void Cancel() override;
private:
void Prepare();
void InitCache();
@ -57,10 +59,10 @@ private:
BLOCK_READAHEAD = 4,
};
s64 filesize_;
s64 filesize_ = 0;
FileLoader *backend_;
int exists_;
int isDirectory_;
int exists_ = -1;
int isDirectory_ = -1;
u64 generation_;
u64 oldestGeneration_;
size_t cacheSize_;
@ -77,6 +79,6 @@ private:
std::map<s64, BlockInfo> blocks_;
std::recursive_mutex blocksMutex_;
bool aheadThread_;
bool aheadThread_ = false;
std::once_flag preparedFlag_;
};

View File

@ -41,19 +41,16 @@ std::mutex DiskCachingFileLoader::cachesMutex_;
// Takes ownership of backend.
DiskCachingFileLoader::DiskCachingFileLoader(FileLoader *backend)
: prepared_(false), filesize_(0), backend_(backend), cache_(nullptr) {
: backend_(backend) {
}
void DiskCachingFileLoader::Prepare() {
if (prepared_) {
return;
}
prepared_ = true;
filesize_ = backend_->FileSize();
if (filesize_ > 0) {
InitCache();
}
std::call_once(preparedFlag_, [this]() {
filesize_ = backend_->FileSize();
if (filesize_ > 0) {
InitCache();
}
});
}
DiskCachingFileLoader::~DiskCachingFileLoader() {
@ -118,6 +115,10 @@ size_t DiskCachingFileLoader::ReadAt(s64 absolutePos, size_t bytes, void *data,
return readSize;
}
void DiskCachingFileLoader::Cancel() {
backend_->Cancel();
}
std::vector<std::string> DiskCachingFileLoader::GetCachedPathsInUse() {
std::lock_guard<std::mutex> guard(cachesMutex_);
@ -156,7 +157,7 @@ void DiskCachingFileLoader::ShutdownCache() {
}
DiskCachingFileLoaderCache::DiskCachingFileLoaderCache(const std::string &path, u64 filesize)
: refCount_(0), filesize_(filesize), origPath_(path), f_(nullptr), fd_(0) {
: filesize_(filesize), origPath_(path) {
InitCache(path);
}

View File

@ -43,6 +43,8 @@ public:
}
size_t ReadAt(s64 absolutePos, size_t bytes, void *data, Flags flags = Flags::NONE) override;
void Cancel() override;
static std::vector<std::string> GetCachedPathsInUse();
private:
@ -50,10 +52,10 @@ private:
void InitCache();
void ShutdownCache();
bool prepared_;
s64 filesize_;
std::once_flag preparedFlag_;
s64 filesize_ = 0;
FileLoader *backend_;
DiskCachingFileLoaderCache *cache_;
DiskCachingFileLoaderCache *cache_ = nullptr;
// 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.
@ -139,7 +141,7 @@ private:
INVALID_INDEX = 0xFFFFFFFF,
};
int refCount_;
int refCount_ = 0;
s64 filesize_;
u32 blockSize_;
u16 generation_;
@ -176,8 +178,8 @@ private:
std::vector<BlockInfo> index_;
std::vector<u32> blockIndexLookup_;
FILE *f_;
int fd_;
FILE *f_ = nullptr;
int fd_ = 0;
static std::string cacheDir_;
};

View File

@ -22,7 +22,7 @@
#include "Core/FileLoaders/HTTPFileLoader.h"
HTTPFileLoader::HTTPFileLoader(const std::string &filename)
: filesize_(0), filepos_(0), url_(filename), filename_(filename), connected_(false) {
: url_(filename), filename_(filename) {
}
void HTTPFileLoader::Prepare() {
@ -33,6 +33,10 @@ void HTTPFileLoader::Prepare() {
}
Connect();
if (!connected_) {
return;
}
int err = client_.SendRequest("HEAD", url_.Resource().c_str());
if (err < 0) {
Disconnect();
@ -123,6 +127,9 @@ size_t HTTPFileLoader::ReadAt(s64 absolutePos, size_t bytes, void *data, Flags f
}
Connect();
if (!connected_) {
return 0;
}
char requestHeaders[4096];
// 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;
return readBytes;
}
void HTTPFileLoader::Connect() {
if (!connected_) {
cancelConnect_ = false;
// Latency is important here, so reduce the timeout.
connected_ = client_.Connect(3, 10.0, &cancelConnect_);
}
}

View File

@ -41,14 +41,14 @@ public:
}
virtual size_t ReadAt(s64 absolutePos, size_t bytes, void *data, Flags flags = Flags::NONE) override;
void Cancel() override {
cancelConnect_ = true;
}
private:
void Prepare();
void Connect() {
if (!connected_) {
connected_ = client_.Connect();
}
}
void Connect();
void Disconnect() {
if (connected_) {
@ -57,12 +57,13 @@ private:
connected_ = false;
}
s64 filesize_;
s64 filepos_;
s64 filesize_ = 0;
s64 filepos_ = 0;
Url url_;
http::Client client_;
std::string filename_;
bool connected_;
bool connected_ = false;
bool cancelConnect_ = false;
std::once_flag preparedFlag_;
std::mutex readAtMutex_;

View File

@ -28,7 +28,7 @@
// Takes ownership of backend.
RamCachingFileLoader::RamCachingFileLoader(FileLoader *backend)
: filesize_(0), backend_(backend), exists_(-1), isDirectory_(-1), aheadThread_(false) {
: backend_(backend) {
filesize_ = backend->FileSize();
if (filesize_ > 0) {
InitCache();
@ -107,11 +107,7 @@ void RamCachingFileLoader::InitCache() {
}
void RamCachingFileLoader::ShutdownCache() {
{
std::lock_guard<std::mutex> guard(blocksMutex_);
// Try to have the thread stop.
aheadRemaining_ = 0;
}
Cancel();
// We can't delete while the thread is running, so have to wait.
// 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) {
s64 cacheStartPos = pos >> BLOCK_SHIFT;
s64 cacheEndPos = (pos + bytes - 1) >> BLOCK_SHIFT;
@ -220,10 +225,11 @@ void RamCachingFileLoader::StartReadAhead(s64 pos) {
}
aheadThread_ = true;
aheadCancel_ = false;
std::thread th([this] {
setCurrentThreadName("FileLoaderReadAhead");
while (aheadRemaining_ != 0) {
while (aheadRemaining_ != 0 && !aheadCancel_) {
// Where should we look?
const u32 cacheStartPos = NextAheadBlock();
if (cacheStartPos == 0xFFFFFFFF) {

View File

@ -39,6 +39,8 @@ public:
}
size_t ReadAt(s64 absolutePos, size_t bytes, void *data, Flags flags = Flags::NONE) override;
void Cancel() override;
private:
void InitCache();
void ShutdownCache();
@ -55,15 +57,16 @@ private:
BLOCK_READAHEAD = 4,
};
s64 filesize_;
s64 filesize_ = 0;
FileLoader *backend_;
u8 *cache_;
int exists_;
int isDirectory_;
u8 *cache_ = nullptr;
int exists_ = -1;
int isDirectory_ = -1;
std::vector<u8> blocks_;
std::mutex blocksMutex_;
u32 aheadRemaining_;
s64 aheadPos_;
bool aheadThread_;
bool aheadThread_ = false;
bool aheadCancel_ = false;
};

View File

@ -72,3 +72,7 @@ size_t RetryingFileLoader::ReadAt(s64 absolutePos, size_t bytes, void *data, Fla
return readSize;
}
void RetryingFileLoader::Cancel() {
backend_->Cancel();
}

View File

@ -36,6 +36,8 @@ public:
}
size_t ReadAt(s64 absolutePos, size_t bytes, void *data, Flags flags = Flags::NONE) override;
void Cancel() override;
private:
enum {
MAX_RETRIES = 3,

View File

@ -86,6 +86,10 @@ public:
virtual size_t ReadAt(s64 absolutePos, size_t bytes, void *data, Flags flags = Flags::NONE) {
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) {