forked from mia/Aegisub
Extract the cache cleaning logic from FFmpegSourceProvider
Originally committed to SVN as r6653.
This commit is contained in:
parent
2a324a56e5
commit
bd0f6a4c2b
5 changed files with 132 additions and 142 deletions
|
@ -55,6 +55,7 @@
|
|||
#include "main.h"
|
||||
#include "md5.h"
|
||||
#include "standard_paths.h"
|
||||
#include "utils.h"
|
||||
|
||||
#ifdef WIN32
|
||||
static void deinit_com(bool) {
|
||||
|
@ -79,8 +80,6 @@ FFmpegSourceProvider::FFmpegSourceProvider()
|
|||
FFMS_Init(0, 1);
|
||||
}
|
||||
|
||||
wxMutex FFmpegSourceProvider::CleaningInProgress;
|
||||
|
||||
/// @brief Callback function that updates the indexing progress dialog
|
||||
/// @param Current The current file positition in bytes
|
||||
/// @param Total The total file size in bytes
|
||||
|
@ -263,127 +262,12 @@ wxString FFmpegSourceProvider::GetCacheFilename(const wxString& _filename)
|
|||
return dirfn.GetShortPath() + "/" + fn.GetFullName();
|
||||
}
|
||||
|
||||
|
||||
/// @brief Starts the cache cleaner thread
|
||||
/// @return True on success, false if the thread could not be started.
|
||||
bool FFmpegSourceProvider::CleanCache() {
|
||||
LOG_D("provider/ffmpegsource/cache") << "attempting to start thread";
|
||||
|
||||
FFmpegSourceCacheCleaner *CleaningThread = new FFmpegSourceCacheCleaner(this);
|
||||
|
||||
if (CleaningThread->Create() != wxTHREAD_NO_ERROR) {
|
||||
LOG_D("provider/ffmpegsource/cache") << "thread creation failed";
|
||||
delete CleaningThread;
|
||||
CleaningThread = NULL;
|
||||
return false;
|
||||
}
|
||||
if (CleaningThread->Run() != wxTHREAD_NO_ERROR) {
|
||||
LOG_D("provider/ffmpegsource/cache") << "failed to start thread";
|
||||
delete CleaningThread;
|
||||
CleaningThread = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
LOG_D("provider/ffmpegsource/cache") << "thread started successfully";
|
||||
return true;
|
||||
void FFmpegSourceProvider::CleanCache() {
|
||||
::CleanCache(StandardPaths::DecodePath("?local/ffms2cache/"),
|
||||
"*.ffindex",
|
||||
OPT_GET("Provider/FFmpegSource/Cache/Size")->GetInt(),
|
||||
OPT_GET("Provider/FFmpegSource/Cache/Files")->GetInt());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief constructor
|
||||
/// @param par the parent provider
|
||||
FFmpegSourceCacheCleaner::FFmpegSourceCacheCleaner(FFmpegSourceProvider *par) : wxThread(wxTHREAD_DETACHED) {
|
||||
parent = par;
|
||||
}
|
||||
|
||||
|
||||
/// @brief Cleans the ffms2 index cache folder
|
||||
/// @return Returns non-0 on error, 0 otherwise.
|
||||
wxThread::ExitCode FFmpegSourceCacheCleaner::Entry() {
|
||||
wxMutexLocker lock(FFmpegSourceProvider::CleaningInProgress);
|
||||
if (!lock.IsOk()) {
|
||||
LOG_D("provider/ffmpegsource/cache") << "cleaning already in progress, thread exiting";
|
||||
return (wxThread::ExitCode)1;
|
||||
}
|
||||
|
||||
wxString cachedirname = StandardPaths::DecodePath("?local/ffms2cache/");
|
||||
wxDir cachedir;
|
||||
if (!cachedir.Open(cachedirname)) {
|
||||
LOG_D("provider/ffmpegsource/cache") << "couldn't open cache directory " << STD_STR(cachedirname);
|
||||
return (wxThread::ExitCode)1;
|
||||
}
|
||||
|
||||
// sleep for a bit so we (hopefully) don't thrash the disk too much while indexing is in progress
|
||||
wxThread::This()->Sleep(2000);
|
||||
|
||||
// the option is in megabytes, we need bytes
|
||||
// shift left by 20 is CLEARLY more efficient than multiplying by 1048576
|
||||
int64_t maxsize = OPT_GET("Provider/FFmpegSource/Cache/Size")->GetInt() << 20;
|
||||
int64_t cursize = wxDir::GetTotalSize(cachedirname).GetValue();
|
||||
int maxfiles = OPT_GET("Provider/FFmpegSource/Cache/Files")->GetInt();
|
||||
|
||||
if (!cachedir.HasFiles("*.ffindex")) {
|
||||
LOG_D("provider/ffmpegsource/cache") << "no index files in cache folder, exiting";
|
||||
return (wxThread::ExitCode)0;
|
||||
}
|
||||
|
||||
int deleted = 0;
|
||||
int numfiles = 0;
|
||||
std::multimap<int64_t,wxFileName> cachefiles;
|
||||
wxString curfn_str;
|
||||
wxFileName curfn;
|
||||
wxDateTime curatime;
|
||||
|
||||
// unusually paranoid sanity check
|
||||
// (someone might have deleted the file(s) after we did HasFiles() above; does wxDir.Open() lock the dir?)
|
||||
if (!cachedir.GetFirst(&curfn_str, "*.ffindex", wxDIR_FILES)) {
|
||||
LOG_D("provider/ffmpegsource/cache") << "undefined error";
|
||||
return (wxThread::ExitCode)1;
|
||||
}
|
||||
|
||||
numfiles++;
|
||||
curfn = wxFileName(cachedirname, curfn_str);
|
||||
curfn.GetTimes(&curatime, NULL, NULL);
|
||||
// FIXME: will break when the time_t's wrap around!!1!
|
||||
cachefiles.insert(std::pair<int64_t,wxFileName>(curatime.GetTicks(),curfn));
|
||||
|
||||
while (cachedir.GetNext(&curfn_str)) {
|
||||
curfn = wxFileName(cachedirname, curfn_str);
|
||||
curfn.GetTimes(&curatime, NULL, NULL);
|
||||
cachefiles.insert(std::pair<int64_t,wxFileName>(curatime.GetTicks(),curfn));
|
||||
numfiles++;
|
||||
|
||||
wxThread::This()->Sleep(250);
|
||||
}
|
||||
|
||||
if (numfiles <= maxfiles && cursize <= maxsize) {
|
||||
LOG_D("provider/ffmpegsource/cache") << "cache does not need cleaning (maxsize=" << (int)maxsize << ", cursize=" << (int)cursize << "; maxfiles=" << maxfiles << "numfiles=" << numfiles << ",exiting";
|
||||
return (wxThread::ExitCode)0;
|
||||
}
|
||||
|
||||
for (std::multimap<int64_t,wxFileName>::iterator i = cachefiles.begin(); i != cachefiles.end(); i++) {
|
||||
// stop cleaning?
|
||||
if ((cursize <= maxsize && numfiles <= maxfiles) || numfiles <= 1)
|
||||
break;
|
||||
|
||||
int64_t fsize = i->second.GetSize().GetValue();
|
||||
if (!wxRemoveFile(i->second.GetFullPath())) {
|
||||
LOG_D("provider/ffmpegsource/cache") << "failed to remove file " << STD_STR(i->second.GetFullPath());
|
||||
continue;
|
||||
}
|
||||
cursize -= fsize;
|
||||
numfiles--;
|
||||
deleted++;
|
||||
|
||||
wxThread::This()->Sleep(250);
|
||||
}
|
||||
|
||||
LOG_D("provider/ffmpegsource/cache") << "deleted " << deleted << " files, exiting";
|
||||
|
||||
return (wxThread::ExitCode)0;
|
||||
}
|
||||
|
||||
|
||||
#endif // WITH_FFMS2
|
||||
|
||||
|
||||
|
|
|
@ -74,9 +74,7 @@ public:
|
|||
FFMS_LOG_DEBUG = 48,
|
||||
};
|
||||
|
||||
/// Mutex preventing two cache cleaner threads from running at the same time
|
||||
static wxMutex CleaningInProgress;
|
||||
bool CleanCache();
|
||||
void CleanCache();
|
||||
|
||||
FFMS_Index *DoIndexing(FFMS_Indexer *Indexer, const wxString& Cachename, int Trackmask, FFMS_IndexErrorHandling IndexEH);
|
||||
std::map<int,wxString> GetTracksOfType(FFMS_Indexer *Indexer, FFMS_TrackType Type);
|
||||
|
@ -88,16 +86,4 @@ public:
|
|||
virtual ~FFmpegSourceProvider() {}
|
||||
};
|
||||
|
||||
/// @class FFmpegSourceCacheCleaner
|
||||
/// @brief Implements index cache cleaning functionality for the FFMS2 providers
|
||||
class FFmpegSourceCacheCleaner : public wxThread {
|
||||
FFmpegSourceProvider *parent;
|
||||
|
||||
public:
|
||||
FFmpegSourceCacheCleaner(FFmpegSourceProvider *par);
|
||||
|
||||
~FFmpegSourceCacheCleaner() {};
|
||||
wxThread::ExitCode Entry();
|
||||
};
|
||||
|
||||
#endif /* WITH_FFMS2 */
|
||||
|
|
|
@ -36,12 +36,15 @@
|
|||
|
||||
#include "config.h"
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
#ifndef AGI_PRE
|
||||
#ifdef __UNIX__
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <map>
|
||||
|
||||
#include <wx/dcmemory.h>
|
||||
#include <wx/dir.h>
|
||||
#include <wx/filename.h>
|
||||
#include <wx/stdpaths.h>
|
||||
#include <wx/window.h>
|
||||
|
@ -53,7 +56,7 @@
|
|||
#include <libaegisub/util_osx.h>
|
||||
#endif
|
||||
|
||||
#include "utils.h"
|
||||
#include "compat.h"
|
||||
|
||||
wxString MakeRelativePath(wxString _path, wxString reference) {
|
||||
if (_path.empty() || _path[0] == '?') return _path;
|
||||
|
@ -305,3 +308,116 @@ bool ForwardMouseWheelEvent(wxWindow *source, wxMouseEvent &evt) {
|
|||
evt.Skip(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
namespace {
|
||||
class cache_cleaner : public wxThread {
|
||||
wxString directory;
|
||||
wxString file_type;
|
||||
int64_t max_size;
|
||||
size_t max_files;
|
||||
|
||||
ExitCode Entry() {
|
||||
static wxMutex cleaning_mutex;
|
||||
wxMutexLocker lock(cleaning_mutex);
|
||||
|
||||
if (!lock.IsOk()) {
|
||||
LOG_D("utils/clean_cache") << "cleaning already in progress, thread exiting";
|
||||
return (ExitCode)1;
|
||||
}
|
||||
|
||||
wxDir cachedir;
|
||||
if (!cachedir.Open(directory)) {
|
||||
LOG_D("utils/clean_cache") << "couldn't open cache directory " << STD_STR(directory);
|
||||
return (wxThread::ExitCode)1;
|
||||
}
|
||||
|
||||
// sleep for a bit so we (hopefully) don't thrash the disk too much while indexing is in progress
|
||||
wxThread::This()->Sleep(2000);
|
||||
|
||||
if (!cachedir.HasFiles(file_type)) {
|
||||
LOG_D("utils/clean_cache") << "no files of the checked type in directory, exiting";
|
||||
return (wxThread::ExitCode)0;
|
||||
}
|
||||
|
||||
// unusually paranoid sanity check
|
||||
// (someone might have deleted the file(s) after we did HasFiles() above; does wxDir.Open() lock the dir?)
|
||||
wxString curfn_str;
|
||||
if (!cachedir.GetFirst(&curfn_str, file_type, wxDIR_FILES)) {
|
||||
LOG_D("utils/clean_cache") << "undefined error";
|
||||
return (wxThread::ExitCode)1;
|
||||
}
|
||||
|
||||
int64_t total_size = 0;
|
||||
std::multimap<int64_t,wxFileName> cachefiles;
|
||||
do {
|
||||
wxFileName curfn(directory, curfn_str);
|
||||
wxDateTime curatime;
|
||||
curfn.GetTimes(&curatime, NULL, NULL);
|
||||
cachefiles.insert(std::make_pair(curatime.GetTicks(), curfn));
|
||||
total_size += curfn.GetSize().GetValue();
|
||||
|
||||
wxThread::This()->Sleep(250);
|
||||
} while (cachedir.GetNext(&curfn_str));
|
||||
|
||||
if (cachefiles.size() <= max_files && total_size <= max_size) {
|
||||
LOG_D("utils/clean_cache")
|
||||
<< "cache does not need cleaning (maxsize=" << max_size
|
||||
<< ", cursize=" << total_size
|
||||
<< "; maxfiles=" << max_files
|
||||
<< ", numfiles=" << cachefiles.size()
|
||||
<< "), exiting";
|
||||
return (wxThread::ExitCode)0;
|
||||
}
|
||||
|
||||
int deleted = 0;
|
||||
for (std::multimap<int64_t,wxFileName>::iterator i = cachefiles.begin(); i != cachefiles.end(); i++) {
|
||||
// stop cleaning?
|
||||
if ((total_size <= max_size && cachefiles.size() - deleted <= max_files) || cachefiles.size() - deleted < 2)
|
||||
break;
|
||||
|
||||
int64_t fsize = i->second.GetSize().GetValue();
|
||||
if (!wxRemoveFile(i->second.GetFullPath())) {
|
||||
LOG_D("utils/clean_cache") << "failed to remove file " << STD_STR(i->second.GetFullPath());
|
||||
continue;
|
||||
}
|
||||
|
||||
total_size -= fsize;
|
||||
++deleted;
|
||||
|
||||
wxThread::This()->Sleep(250);
|
||||
}
|
||||
|
||||
LOG_D("utils/clean_cache") << "deleted " << deleted << " files, exiting";
|
||||
return (wxThread::ExitCode)0;
|
||||
}
|
||||
|
||||
public:
|
||||
cache_cleaner(wxString const& directory, wxString const& file_type, int64_t max_size, int64_t max_files)
|
||||
: wxThread(wxTHREAD_DETACHED)
|
||||
, directory(directory)
|
||||
, file_type(file_type)
|
||||
, max_size(max_size << 20)
|
||||
{
|
||||
if (max_files < 1)
|
||||
this->max_files = (size_t)-1;
|
||||
else
|
||||
this->max_files = (size_t)max_files;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void CleanCache(wxString const& directory, wxString const& file_type, int64_t max_size, int64_t max_files) {
|
||||
LOG_D("utils/clean_cache") << "attempting to start cleaner thread";
|
||||
wxThread *CleaningThread = new cache_cleaner(directory, file_type, max_size, max_files);
|
||||
|
||||
if (CleaningThread->Create() != wxTHREAD_NO_ERROR) {
|
||||
LOG_D("utils/clean_cache") << "thread creation failed";
|
||||
delete CleaningThread;
|
||||
}
|
||||
else if (CleaningThread->Run() != wxTHREAD_NO_ERROR) {
|
||||
LOG_D("utils/clean_cache") << "failed to start thread";
|
||||
delete CleaningThread;
|
||||
}
|
||||
|
||||
LOG_D("utils/clean_cache") << "thread started successfully";
|
||||
}
|
||||
|
|
|
@ -100,6 +100,12 @@ void RestartAegisub();
|
|||
/// @return Should the calling code process the event?
|
||||
bool ForwardMouseWheelEvent(wxWindow *source, wxMouseEvent &evt);
|
||||
|
||||
/// Clean up the given cache directory, limiting the size to max_size
|
||||
/// @param directory Directory to clean
|
||||
/// @param file_type Wildcard pattern for files to clean up
|
||||
/// @param max_size Maximum size of directory in MB
|
||||
/// @param max_files Maximum number of files
|
||||
void CleanCache(wxString const& directory, wxString const& file_type, int64_t max_size, int64_t max_files = -1);
|
||||
|
||||
/// @brief Templated abs() function
|
||||
template <typename T> T tabs(T x) { return x < 0 ? -x : x; }
|
||||
|
|
|
@ -138,9 +138,7 @@ void FFmpegSourceVideoProvider::LoadVideo(wxString filename) {
|
|||
wxFileName(CacheName).Touch();
|
||||
|
||||
// we have now read the index and may proceed with cleaning the index cache
|
||||
if (!CleanCache()) {
|
||||
//do something?
|
||||
}
|
||||
CleanCache();
|
||||
|
||||
// track number still not set?
|
||||
if (TrackNumber < 0) {
|
||||
|
|
Loading…
Reference in a new issue