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