tahoma2d/toonz/sources/common/tfx/tcacheresourcepool.cpp

295 lines
8.6 KiB
C++
Raw Normal View History

2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
// Qt includes
2016-03-19 06:57:51 +13:00
#include <QMap>
#include <QSettings>
#include <QDate>
#include <QDir>
#include <QFileInfo>
#include <QFileInfoList>
//#define USE_SQLITE_HDPOOL
#ifdef USE_SQLITE_HDPOOL
2016-06-15 18:43:10 +12:00
// SQLite include
2016-03-19 06:57:51 +13:00
#include "sqlite/sqlite3.h"
#endif
#include "tcacheresourcepool.h"
2016-06-15 18:43:10 +12:00
// Debug
2016-03-19 06:57:51 +13:00
//#define DIAGNOSTICS
//#include "diagnostics.h"
//******************************************************************************************
// Cache Resource Pool BACKED ON DISK
//******************************************************************************************
2016-06-15 18:43:10 +12:00
// STILL UNDER DEVELOPMENT...
class THDCacheResourcePool {
2016-03-19 06:57:51 +13:00
public:
2016-06-15 18:43:10 +12:00
THDCacheResourcePool() {}
~THDCacheResourcePool() {}
2016-03-19 06:57:51 +13:00
};
//*************************************************************************************
// Cache resource pool methods involved with HD Pool management
//*************************************************************************************
2016-06-15 18:43:10 +12:00
inline bool TCacheResourcePool::isHDActive() {
2016-03-19 06:57:51 +13:00
#ifdef USE_SQLITE_HDPOOL
2016-06-15 18:43:10 +12:00
return m_hdPool && m_hdPool->isActive();
2016-03-19 06:57:51 +13:00
#else
2016-06-15 18:43:10 +12:00
return false;
2016-03-19 06:57:51 +13:00
#endif
}
//-----------------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
void TCacheResourcePool::reset() { setPath("", "", ""); }
2016-03-19 06:57:51 +13:00
//----------------------------------------------------------------------
// Prevents the resources in memory from backing to disk. Observe that
// the actual content of the resource is NOT invalidated - since resources
// are intended as 'reference-protected' material which is expected to last
// as long as references are held.
2016-06-15 18:43:10 +12:00
void TCacheResourcePool::invalidateAll() {
QMutexLocker locker(&m_memMutex);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
MemResources::iterator it;
for (it = m_memResources.begin(); it != m_memResources.end(); ++it)
it->second->invalidate();
2016-03-19 06:57:51 +13:00
}
//----------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
inline QString TCacheResourcePool::getPoolRoot(QString cacheRoot,
QString projectName,
QString sceneName) {
return QString(cacheRoot + "/render/" + projectName + "/" + sceneName + "/");
2016-03-19 06:57:51 +13:00
}
//----------------------------------------------------------------------
//! Connects to the pool associated to the given project/scene pair.
//! \warning As this closes the current connection before opening a new one,
//! make sure that no pool access happens at this point. You should also
//! verify that no resource from the old pair still exists.
2016-06-15 18:43:10 +12:00
void TCacheResourcePool::setPath(QString cacheRoot, QString projectName,
QString sceneName) {
// There should be no resource in memory.
assert(m_memResources.empty());
// However, just in case, invalidate all resources so that no more resource
// backing
// operation take place for current resources, from now on.
// No care is paid as to whether active transactions currently exist. You
// have been warned by the way....
invalidateAll();
delete m_hdPool;
m_hdPool = 0;
m_path = TFilePath();
2016-03-19 06:57:51 +13:00
#ifdef USE_SQLITE_HDPOOL
2016-06-15 18:43:10 +12:00
if (!(cacheRoot.isEmpty() || projectName.isEmpty() || sceneName.isEmpty())) {
QString hdPoolRoot(getPoolRoot(cacheRoot, projectName, sceneName));
m_hdPool = new THDCacheResourcePool(hdPoolRoot);
m_path = m_hdPool->getResourcesFilePath();
}
2016-03-19 06:57:51 +13:00
#endif
}
//-----------------------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
void TCacheResourcePool::startBacking(TCacheResource *resource) {
assert(isHDActive());
if (!isHDActive()) return;
2016-03-19 06:57:51 +13:00
#ifdef USE_SQLITE_HDPOOL
2016-06-15 18:43:10 +12:00
resource->m_backEnabled = true;
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
m_hdPool->buildBackingPath(resource);
2016-03-19 06:57:51 +13:00
#endif
}
//******************************************************************************************
// Cache resource pool implementation
//******************************************************************************************
2016-06-15 18:43:10 +12:00
TCacheResourcePool *TCacheResourcePool::instance() {
static TCacheResourcePool theInstance;
return &theInstance;
2016-03-19 06:57:51 +13:00
}
//----------------------------------------------------------------------
TCacheResourcePool::TCacheResourcePool()
2016-06-15 18:43:10 +12:00
: m_memMutex(QMutex::Recursive)
, m_searchCount(0)
, m_foundIterator(false)
, m_searchIterator(m_memResources.end())
, m_hdPool(0)
, m_path() {
// Open the settings for cache retrieval
2016-03-19 06:57:51 +13:00
}
//----------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
TCacheResourcePool::~TCacheResourcePool() {
// Temporary
// performAutomaticCleanup();
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
delete m_hdPool;
2016-03-19 06:57:51 +13:00
}
//----------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
const TFilePath &TCacheResourcePool::getPath() const { return m_path; }
2016-03-19 06:57:51 +13:00
//----------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
//! Initializes an optimized search on the pool for a specific resource, caching
//! successive
2016-03-19 06:57:51 +13:00
//! results.
2016-06-15 18:43:10 +12:00
//! \note Pool searches are serialized, and calls to this method lock the pool's
//! mutex until a
2016-03-19 06:57:51 +13:00
//! corresponding number of endCachedSearch() methods are invoked.
2016-06-15 18:43:10 +12:00
void TCacheResourcePool::beginCachedSearch() {
m_memMutex.lock();
m_searchCount++;
2016-03-19 06:57:51 +13:00
}
//----------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
//! The inverse to beginCachedSearch(). This method \b MUST be called in
//! correspondence to
2016-03-19 06:57:51 +13:00
//! beginCachedSearch() calls.
2016-06-15 18:43:10 +12:00
void TCacheResourcePool::endCachedSearch() {
if (--m_searchCount <= 0) {
m_foundIterator = false;
m_searchIterator = m_memResources.end();
}
m_memMutex.unlock();
2016-03-19 06:57:51 +13:00
}
//----------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
//! Attempts retrieval of the resource with specified name, and eventually
//! creates it if
2016-03-19 06:57:51 +13:00
//! the createIfNone parameter is set.
2016-06-15 18:43:10 +12:00
TCacheResource *TCacheResourcePool::getResource(const std::string &name,
bool createIfNone) {
// DIAGNOSTICS_TIMER("#times.txt | getResource Overall time");
// DIAGNOSTICS_MEANTIMER("#times.txt | getResource Mean time");
TCacheResource *result = 0;
// NOTA: Passa ad un oggetto lockatore. Quello e' in grado di gestire i casi
// di eccezioni ecc..
beginCachedSearch();
// Search for an already allocated resource
if (m_searchIterator == m_memResources.end()) {
m_searchIterator = m_memResources.lower_bound(name);
2020-04-12 17:19:20 +12:00
if (m_searchIterator != m_memResources.end()) {
if (!(name < m_searchIterator->first)) {
2016-06-15 18:43:10 +12:00
m_foundIterator = true;
2020-04-12 17:19:20 +12:00
} else if (m_searchIterator != m_memResources.begin()) {
2016-06-15 18:43:10 +12:00
m_searchIterator--;
2020-04-12 17:19:20 +12:00
}
}
2016-06-15 18:43:10 +12:00
}
if (m_foundIterator) {
result = m_searchIterator->second;
endCachedSearch();
return result;
}
{
QString resourcePath;
QString resourceFlags;
if (isHDActive()) {
2016-03-19 06:57:51 +13:00
#ifdef USE_SQLITE_HDPOOL
2016-06-15 18:43:10 +12:00
// DIAGNOSTICS_TIMER("#times.txt | HDPOOL getResource Overall time");
// DIAGNOSTICS_MEANTIMER("#times.txt | HDPOOL getResource Mean time");
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
// Search in the HD pool
ReadQuery query(m_hdPool);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
bool ret =
query.prepare("SELECT Path, Flags FROM Resources WHERE Name = '" +
QString::fromStdString(name) + "';");
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
// If an error occurred, assume the resource does not exist. Doing nothing
// works fine.
assert(ret);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
if (query.step()) {
resourcePath = query.value(0);
resourceFlags = query.value(1);
}
2016-03-19 06:57:51 +13:00
#endif
2016-06-15 18:43:10 +12:00
}
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
if (!resourcePath.isEmpty() || createIfNone) {
TCacheResource *result = new TCacheResource;
result->m_pos = m_searchIterator =
m_memResources.insert(m_searchIterator, std::make_pair(name, result));
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
// DIAGNOSTICS_STRSET("#resources.txt | RISORSE | " + QString::number((UINT)
// result) + " | Name",
// QString::fromStdString(name).left(70));
2016-03-19 06:57:51 +13:00
#ifdef USE_SQLITE_HDPOOL
2016-06-15 18:43:10 +12:00
if (isHDActive()) m_hdPool->loadResourceInfos(result, resourcePath);
2016-03-19 06:57:51 +13:00
#endif
2016-06-15 18:43:10 +12:00
m_foundIterator = true;
endCachedSearch();
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
return result;
}
}
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
endCachedSearch();
return 0;
2016-03-19 06:57:51 +13:00
}
//----------------------------------------------------------------------
2016-06-15 18:43:10 +12:00
void TCacheResourcePool::releaseResource(TCacheResource *resource) {
QMutexLocker locker(&m_memMutex);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
// Re-check the resource's reference count. This is necessary since a
// concurrent
// thread may have locked the memMutex for resource retrieval BEFORE this one.
// If that is the case, the resource's refCount has increased back above 0.
if (resource->m_refCount > 0) return;
2016-03-19 06:57:51 +13:00
#ifdef USE_SQLITE_HDPOOL
2016-06-15 18:43:10 +12:00
QMutexLocker flushLocker(isHDActive() ? &m_hdPool->m_flushMutex : 0);
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
if (isHDActive()) {
// Flush all resource updates as this resource is being destroyed
m_hdPool->flushResources();
2016-03-19 06:57:51 +13:00
2016-06-15 18:43:10 +12:00
// Save the resource infos
m_hdPool->saveResourceInfos(resource);
}
2016-03-19 06:57:51 +13:00
#endif
2016-06-15 18:43:10 +12:00
m_memResources.erase(resource->m_pos);
delete resource;
2016-03-19 06:57:51 +13:00
}