diff --git a/rtgui/cachemanager.cc b/rtgui/cachemanager.cc index a7029951a..612f5be27 100644 --- a/rtgui/cachemanager.cc +++ b/rtgui/cachemanager.cc @@ -24,10 +24,26 @@ #include #include -CacheManager cacheMgr; +CacheManager* +CacheManager::getInstance(void) +{ + static CacheManager* instance_ = 0; + if ( instance_ == 0 ) + { + static Glib::Mutex smutex_; + Glib::Mutex::Lock lock(smutex_); + if ( instance_ == 0 ) + { + instance_ = new CacheManager(); + } + } + return instance_; +} void CacheManager::init () { + Glib::Mutex::Lock lock(mutex_); + openEntries.clear (); baseDir = options.cacheBaseDir; @@ -49,12 +65,18 @@ Thumbnail* CacheManager::getEntry (const Glib::ustring& fname) { Thumbnail* res = NULL; - std::map::iterator r = openEntries.find (fname); - // if it is open, return it - if (r!=openEntries.end()) { - r->second->increaseRef (); - return r->second; - } + // take manager lock and search for entry, if found return it else release + // lock and create it + { + Glib::Mutex::Lock lock(mutex_); + + string_thumb_map::iterator r = openEntries.find (fname); + // if it is open, return it + if (r!=openEntries.end()) { + r->second->increaseRef (); + return r->second; + } + } // compute the md5 std::string md5 = getMD5 (fname); @@ -78,6 +100,7 @@ Thumbnail* CacheManager::getEntry (const Glib::ustring& fname) { } // if not, create a new one if (!res) { + res = new Thumbnail (this, fname, md5); if (!res->isSupported ()) { delete res; @@ -85,20 +108,45 @@ Thumbnail* CacheManager::getEntry (const Glib::ustring& fname) { } } + // retake the lock and see if it was added while we we're unlocked, if it + // was use it over our version. if not added we create the cache entry if (res) - openEntries[fname] = res; + { + Glib::Mutex::Lock lock(mutex_); + + string_thumb_map::iterator r = openEntries.find (fname); + if (r!=openEntries.end()) { + delete res; + r->second->increaseRef (); + return r->second; + } + + // it wasn't, create a new entry + openEntries[fname] = res; + } + return res; } void CacheManager::deleteEntry (const Glib::ustring& fname) { + Glib::Mutex::Lock lock(mutex_); + // check if it is opened - std::map::iterator r = openEntries.find (fname); + string_thumb_map::iterator r = openEntries.find (fname); // if it is open, dont delete it if (r!=openEntries.end()) { std::string md5 = r->second->getMD5 (); - r->second->decreaseRef (); + + // decrease reference count; this will call back into CacheManager so + // we release the lock for it. + { + lock.release(); + r->second->decreaseRef (); + lock.acquire(); + } + // if in the editor, the thumbnail still exists. If not, delete it: r = openEntries.find (fname); if (r==openEntries.end() && md5!="") { @@ -126,6 +174,8 @@ void CacheManager::deleteEntry (const Glib::ustring& fname) { void CacheManager::renameEntry (const std::string& oldfilename, const std::string& oldmd5, const std::string& newfilename) { + Glib::Mutex::Lock lock(mutex_); + std::string newmd5 = getMD5 (newfilename); ::g_rename ((getCacheFileName ("profiles", oldfilename, oldmd5) + paramFileExtension).c_str(), (getCacheFileName ("profiles", newfilename, newmd5) + paramFileExtension).c_str()); @@ -136,7 +186,7 @@ void CacheManager::renameEntry (const std::string& oldfilename, const std::strin ::g_rename ((getCacheFileName ("data", oldfilename, oldmd5) + ".txt").c_str(), (getCacheFileName ("data", newfilename, newmd5) + ".txt").c_str()); // check if it is opened - std::map::iterator r = openEntries.find (oldfilename); + string_thumb_map::iterator r = openEntries.find (oldfilename); // if it is open, update md5 if (r!=openEntries.end()) { Thumbnail* t = r->second; @@ -150,8 +200,10 @@ void CacheManager::renameEntry (const std::string& oldfilename, const std::strin void CacheManager::closeThumbnail (Thumbnail* t) { + Glib::Mutex::Lock lock(mutex_); + t->updateCache (); - std::map::iterator r = openEntries.find (t->getFileName()); + string_thumb_map::iterator r = openEntries.find (t->getFileName()); if (r!=openEntries.end()) openEntries.erase (r); delete t; @@ -159,11 +211,15 @@ void CacheManager::closeThumbnail (Thumbnail* t) { void CacheManager::closeCache () { + Glib::Mutex::Lock lock(mutex_); + applyCacheSizeLimitation (); } void CacheManager::clearAll () { + Glib::Mutex::Lock lock(mutex_); + deleteDir ("images"); deleteDir ("aehistograms"); deleteDir ("embprofiles"); @@ -171,7 +227,7 @@ void CacheManager::clearAll () { deleteDir ("data"); // re-generate thumbnail images and clear profiles of open thumbnails - std::map::iterator i; + string_thumb_map::iterator i; for (i=openEntries.begin(); i!=openEntries.end(); i++) { i->second->clearProcParams (CACHEMGR); i->second->generateThumbnailImage (); @@ -180,21 +236,25 @@ void CacheManager::clearAll () { } void CacheManager::clearThumbImages () { + Glib::Mutex::Lock lock(mutex_); + deleteDir ("images"); deleteDir ("aehistograms"); deleteDir ("embprofiles"); // re-generate thumbnail images of open thumbnails - std::map::iterator i; + string_thumb_map::iterator i; for (i=openEntries.begin(); i!=openEntries.end(); i++) i->second->generateThumbnailImage (); } void CacheManager::clearProfiles () { + Glib::Mutex::Lock lock(mutex_); + deleteDir ("profiles"); // clear profiles of open thumbnails - std::map::iterator i; + string_thumb_map::iterator i; for (i=openEntries.begin(); i!=openEntries.end(); i++) i->second->clearProcParams (CACHEMGR); } @@ -234,9 +294,9 @@ void CacheManager::applyCacheSizeLimitation () { std::vector flist; Glib::ustring dataDir = Glib::build_filename (baseDir, "data"); Glib::RefPtr dir = Gio::File::create_for_path (dataDir); - - safe_build_file_list (dir, flist); - + + safe_build_file_list (dir, flist); + if (flist.size() > options.maxCacheEntries) { std::sort (flist.begin(), flist.end()); while (flist.size() > options.maxCacheEntries) { @@ -245,7 +305,7 @@ void CacheManager::applyCacheSizeLimitation () { ::g_remove ((Glib::build_filename (Glib::build_filename (baseDir, "images"), flist.front().fname) + ".jpg").c_str()); ::g_remove ((Glib::build_filename (Glib::build_filename (baseDir, "aehistograms"), flist.front().fname)).c_str()); ::g_remove ((Glib::build_filename (Glib::build_filename (baseDir, "embprofiles"), flist.front().fname) + ".icc").c_str()); -// ::g_remove ((Glib::build_filename (Glib::build_filename (baseDir, "profiles"), flist.front().fname) + paramFileExtension).c_str()); + // ::g_remove ((Glib::build_filename (Glib::build_filename (baseDir, "profiles"), flist.front().fname) + paramFileExtension).c_str()); flist.erase (flist.begin()); } } diff --git a/rtgui/cachemanager.h b/rtgui/cachemanager.h index f2f15c59d..983c2acbd 100644 --- a/rtgui/cachemanager.h +++ b/rtgui/cachemanager.h @@ -29,14 +29,21 @@ class Thumbnail; class CacheManager { - std::map openEntries; - Glib::ustring baseDir; + typedef std::pair string_thumb_pair; + typedef std::map string_thumb_map; + + string_thumb_map openEntries; + Glib::ustring baseDir; + Glib::Mutex mutex_; void deleteDir (const Glib::ustring& dirName); - public: CacheManager () {} + public: + + static CacheManager* getInstance(void); + void init (); Thumbnail* getEntry (const Glib::ustring& fname); void deleteEntry (const Glib::ustring& fname); @@ -44,7 +51,7 @@ class CacheManager { void closeThumbnail (Thumbnail* t); - const Glib::ustring& getBaseDir () { return baseDir; } + const Glib::ustring& getBaseDir () { Glib::Mutex::Lock lock(mutex_); return baseDir; } void closeCache (); static std::string getMD5 (const Glib::ustring& fname); @@ -58,7 +65,7 @@ class CacheManager { Glib::ustring getCacheFileName (const Glib::ustring& subdir, const Glib::ustring& fname, const Glib::ustring& md5); }; -extern CacheManager cacheMgr; +#define cacheMgr CacheManager::getInstance() #endif diff --git a/rtgui/filecatalog.cc b/rtgui/filecatalog.cc index 36cd269c2..1adb54e69 100644 --- a/rtgui/filecatalog.cc +++ b/rtgui/filecatalog.cc @@ -392,7 +392,7 @@ void PreviewLoader::start () { void PreviewLoader::process (DirEntry& current) { if (Glib::file_test (current.fullName, Glib::FILE_TEST_EXISTS)) { - Thumbnail* tmb = cacheMgr.getEntry (current.fullName); + Thumbnail* tmb = cacheMgr->getEntry (current.fullName); if (tmb && pl) pl->previewReady (new FileBrowserEntry (tmb, current.fullName)); } @@ -475,7 +475,7 @@ void FileCatalog::deleteRequested (std::vector tbe) { // t->thumbnail->decreaseRef (); delete t; // remove from cache - cacheMgr.deleteEntry (fname); + cacheMgr->deleteEntry (fname); // delete from file system ::g_remove (fname.c_str()); // delete paramfile if found @@ -538,7 +538,7 @@ void FileCatalog::renameRequested (std::vector tbe) { nBaseName += "." + getExtension (baseName); Glib::ustring nfname = Glib::build_filename (dirName, nBaseName); if (!::g_rename (ofname.c_str(), nfname.c_str())) { - cacheMgr.renameEntry (ofname, tbe[i]->thumbnail->getMD5(), nfname); + cacheMgr->renameEntry (ofname, tbe[i]->thumbnail->getMD5(), nfname); reparseDirectory (); } renameDlg->hide (); @@ -584,7 +584,7 @@ void FileCatalog::renameRequested (std::vector tbe) { } Glib::ustring nfname = Glib::build_filename (dirName, nBaseName); if (!::g_rename (ofname.c_str(), nfname.c_str())) { - cacheMgr.renameEntry (ofname, tbe[i]->thumbnail->getMD5(), nfname); + cacheMgr->renameEntry (ofname, tbe[i]->thumbnail->getMD5(), nfname); // the remaining part (removing old and adding new entry) is done by the directory monitor reparseDirectory (); // on_dir_changed (Gio::File::create_for_path (nfname), Gio::File::create_for_path (nfname), Gio::FILE_MONITOR_EVENT_CHANGED, true); @@ -749,7 +749,7 @@ int FileCatalog::reparseDirectory () { fileNamesToDel.push_back (t[i]->filename); for (size_t i=0; idelEntry (fileNamesToDel[i]); - cacheMgr.deleteEntry (fileNamesToDel[i]); + cacheMgr->deleteEntry (fileNamesToDel[i]); } // check if a new file has been added @@ -820,7 +820,7 @@ void FileCatalog::addAndOpenFile (const Glib::ustring& fname) { int lastdot = info->get_name().find_last_of ('.'); if (options.is_extention_enabled(lastdot!=(int)Glib::ustring::npos ? info->get_name().substr (lastdot+1) : "")){ // if supported, load thumbnail first - Thumbnail* tmb = cacheMgr.getEntry (file->get_parse_name()); + Thumbnail* tmb = cacheMgr->getEntry (file->get_parse_name()); if (tmb) { FileBrowserEntry* entry = new FileBrowserEntry (tmb, file->get_parse_name()); previewReady (entry); diff --git a/rtgui/preferences.cc b/rtgui/preferences.cc index 62a1b970d..49a09d7bf 100644 --- a/rtgui/preferences.cc +++ b/rtgui/preferences.cc @@ -1190,7 +1190,7 @@ void Preferences::clearProfilesPressed () { md.set_title (M("PREFERENCES_CLEARDLG_TITLE")); md.show_all (); while (gtk_events_pending ()) gtk_main_iteration (); - cacheMgr.clearProfiles (); + cacheMgr->clearProfiles (); md.hide (); } @@ -1201,7 +1201,7 @@ void Preferences::clearThumbImagesPressed () { md.set_title (M("PREFERENCES_CLEARDLG_TITLE")); md.show_all (); while (gtk_events_pending ()) gtk_main_iteration (); - cacheMgr.clearThumbImages (); + cacheMgr->clearThumbImages (); md.hide (); } @@ -1212,7 +1212,7 @@ void Preferences::clearAllPressed () { md.set_title (M("PREFERENCES_CLEARDLG_TITLE")); md.show_all (); while (gtk_events_pending ()) gtk_main_iteration (); - cacheMgr.clearAll (); + cacheMgr->clearAll (); md.hide (); } diff --git a/rtgui/rtwindow.cc b/rtgui/rtwindow.cc index b3c4f0e2f..6dd3cfe40 100644 --- a/rtgui/rtwindow.cc +++ b/rtgui/rtwindow.cc @@ -23,7 +23,7 @@ RTWindow::RTWindow () { - cacheMgr.init (); + cacheMgr->init (); #ifdef GLIBMM_EXCEPTIONS_ENABLED try { set_default_icon_from_file (argv0+"/images/logoicon16.png"); @@ -248,7 +248,7 @@ bool RTWindow::on_delete_event(GdkEventAny* event) { if (options.startupDir==STARTUPDIR_LAST && fileBrowser->lastSelectedDir ()!="") options.startupPath = fileBrowser->lastSelectedDir (); fileBrowser->close (); - cacheMgr.closeCache (); + cacheMgr->closeCache (); options.lastScale = editorPanel->zoomBar->getScale ();