Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
// 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
Shinya Kitaoka 120a6e
// 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
Shinya Kitaoka 120a6e
// 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
Shinya Kitaoka 120a6e
// STILL UNDER DEVELOPMENT...
Shinya Kitaoka 120a6e
class THDCacheResourcePool {
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  THDCacheResourcePool() {}
Shinya Kitaoka 120a6e
  ~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
Shinya Kitaoka 120a6e
inline bool TCacheResourcePool::isHDActive() {
Toshihiro Shimizu 890ddd
#ifdef USE_SQLITE_HDPOOL
Shinya Kitaoka 120a6e
  return m_hdPool && m_hdPool->isActive();
Toshihiro Shimizu 890ddd
#else
Shinya Kitaoka 120a6e
  return false;
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TCacheResourcePool::reset() { setPath("", "", ""); }
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.
Shinya Kitaoka 120a6e
void TCacheResourcePool::invalidateAll() {
Shinya Kitaoka 120a6e
  QMutexLocker locker(&m_memMutex);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  MemResources::iterator it;
Shinya Kitaoka 120a6e
  for (it = m_memResources.begin(); it != m_memResources.end(); ++it)
Shinya Kitaoka 120a6e
    it->second->invalidate();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//----------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
inline QString TCacheResourcePool::getPoolRoot(QString cacheRoot,
Shinya Kitaoka 120a6e
                                               QString projectName,
Shinya Kitaoka 120a6e
                                               QString sceneName) {
Shinya Kitaoka 120a6e
  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.
Shinya Kitaoka 120a6e
void TCacheResourcePool::setPath(QString cacheRoot, QString projectName,
Shinya Kitaoka 120a6e
                                 QString sceneName) {
Shinya Kitaoka 120a6e
  // There should be no resource in memory.
Shinya Kitaoka 120a6e
  assert(m_memResources.empty());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // However, just in case, invalidate all resources so that no more resource
Shinya Kitaoka 120a6e
  // backing
Shinya Kitaoka 120a6e
  // operation take place for current resources, from now on.
Shinya Kitaoka 120a6e
  // No care is paid as to whether active transactions currently exist. You
Shinya Kitaoka 120a6e
  // have been warned by the way....
Shinya Kitaoka 120a6e
  invalidateAll();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  delete m_hdPool;
Shinya Kitaoka 120a6e
  m_hdPool = 0;
Shinya Kitaoka 120a6e
  m_path   = TFilePath();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#ifdef USE_SQLITE_HDPOOL
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (!(cacheRoot.isEmpty() || projectName.isEmpty() || sceneName.isEmpty())) {
Shinya Kitaoka 120a6e
    QString hdPoolRoot(getPoolRoot(cacheRoot, projectName, sceneName));
Shinya Kitaoka 120a6e
    m_hdPool = new THDCacheResourcePool(hdPoolRoot);
Shinya Kitaoka 120a6e
    m_path   = m_hdPool->getResourcesFilePath();
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TCacheResourcePool::startBacking(TCacheResource *resource) {
Shinya Kitaoka 120a6e
  assert(isHDActive());
Shinya Kitaoka 120a6e
  if (!isHDActive()) return;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#ifdef USE_SQLITE_HDPOOL
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  resource->m_backEnabled = true;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  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
Shinya Kitaoka 120a6e
TCacheResourcePool *TCacheResourcePool::instance() {
Shinya Kitaoka 120a6e
  static TCacheResourcePool theInstance;
Shinya Kitaoka 120a6e
  return &theInstance;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//----------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TCacheResourcePool::TCacheResourcePool()
Shinya Kitaoka 120a6e
    : m_memMutex(QMutex::Recursive)
Shinya Kitaoka 120a6e
    , m_searchCount(0)
Shinya Kitaoka 120a6e
    , m_foundIterator(false)
Shinya Kitaoka 120a6e
    , m_searchIterator(m_memResources.end())
Shinya Kitaoka 120a6e
    , m_hdPool(0)
Shinya Kitaoka 120a6e
    , m_path() {
Shinya Kitaoka 120a6e
  // Open the settings for cache retrieval
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//----------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TCacheResourcePool::~TCacheResourcePool() {
Shinya Kitaoka 120a6e
  // Temporary
Shinya Kitaoka 120a6e
  // performAutomaticCleanup();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  delete m_hdPool;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//----------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
const TFilePath &TCacheResourcePool::getPath() const { return m_path; }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//----------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
//! Initializes an optimized search on the pool for a specific resource, caching
Shinya Kitaoka 120a6e
//! successive
Toshihiro Shimizu 890ddd
//! results.
Shinya Kitaoka 120a6e
//! \note Pool searches are serialized, and calls to this method lock the pool's
Shinya Kitaoka 120a6e
//! mutex until a
Toshihiro Shimizu 890ddd
//! corresponding number of endCachedSearch() methods are invoked.
Shinya Kitaoka 120a6e
void TCacheResourcePool::beginCachedSearch() {
Shinya Kitaoka 120a6e
  m_memMutex.lock();
Shinya Kitaoka 120a6e
  m_searchCount++;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//----------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
//! The inverse to beginCachedSearch(). This method \b MUST be called in
Shinya Kitaoka 120a6e
//! correspondence to
Toshihiro Shimizu 890ddd
//! beginCachedSearch() calls.
Shinya Kitaoka 120a6e
void TCacheResourcePool::endCachedSearch() {
Shinya Kitaoka 120a6e
  if (--m_searchCount <= 0) {
Shinya Kitaoka 120a6e
    m_foundIterator  = false;
Shinya Kitaoka 120a6e
    m_searchIterator = m_memResources.end();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  m_memMutex.unlock();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//----------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
//! Attempts retrieval of the resource with specified name, and eventually
Shinya Kitaoka 120a6e
//! creates it if
Toshihiro Shimizu 890ddd
//! the createIfNone parameter is set.
Shinya Kitaoka 120a6e
TCacheResource *TCacheResourcePool::getResource(const std::string &name,
Shinya Kitaoka 120a6e
                                                bool createIfNone) {
Shinya Kitaoka 120a6e
  // DIAGNOSTICS_TIMER("#times.txt | getResource Overall time");
Shinya Kitaoka 120a6e
  // DIAGNOSTICS_MEANTIMER("#times.txt | getResource Mean time");
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TCacheResource *result = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // NOTA: Passa ad un oggetto lockatore. Quello e' in grado di gestire i casi
Shinya Kitaoka 120a6e
  // di eccezioni ecc..
Shinya Kitaoka 120a6e
  beginCachedSearch();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Search for an already allocated resource
Shinya Kitaoka 120a6e
  if (m_searchIterator == m_memResources.end()) {
Shinya Kitaoka 120a6e
    m_searchIterator = m_memResources.lower_bound(name);
Shinya Kitaoka 120a6e
    if (m_searchIterator != m_memResources.end())
Shinya Kitaoka 120a6e
      if (!(name < m_searchIterator->first))
Shinya Kitaoka 120a6e
        m_foundIterator = true;
Shinya Kitaoka 120a6e
      else if (m_searchIterator != m_memResources.begin())
Shinya Kitaoka 120a6e
        m_searchIterator--;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (m_foundIterator) {
Shinya Kitaoka 120a6e
    result = m_searchIterator->second;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    endCachedSearch();
Shinya Kitaoka 120a6e
    return result;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  {
Shinya Kitaoka 120a6e
    QString resourcePath;
Shinya Kitaoka 120a6e
    QString resourceFlags;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (isHDActive()) {
Toshihiro Shimizu 890ddd
#ifdef USE_SQLITE_HDPOOL
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      // DIAGNOSTICS_TIMER("#times.txt | HDPOOL getResource Overall time");
Shinya Kitaoka 120a6e
      // DIAGNOSTICS_MEANTIMER("#times.txt | HDPOOL getResource Mean time");
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      // Search in the HD pool
Shinya Kitaoka 120a6e
      ReadQuery query(m_hdPool);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      bool ret =
Shinya Kitaoka 120a6e
          query.prepare("SELECT Path, Flags FROM Resources WHERE Name = '" +
Shinya Kitaoka 120a6e
                        QString::fromStdString(name) + "';");
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      // If an error occurred, assume the resource does not exist. Doing nothing
Shinya Kitaoka 120a6e
      // works fine.
Shinya Kitaoka 120a6e
      assert(ret);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      if (query.step()) {
Shinya Kitaoka 120a6e
        resourcePath  = query.value(0);
Shinya Kitaoka 120a6e
        resourceFlags = query.value(1);
Shinya Kitaoka 120a6e
      }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#endif
Shinya Kitaoka 120a6e
    }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    if (!resourcePath.isEmpty() || createIfNone) {
Shinya Kitaoka 120a6e
      TCacheResource *result = new TCacheResource;
Shinya Kitaoka 120a6e
      result->m_pos          = m_searchIterator =
Shinya Kitaoka 120a6e
          m_memResources.insert(m_searchIterator, std::make_pair(name, result));
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
// DIAGNOSTICS_STRSET("#resources.txt | RISORSE | " + QString::number((UINT)
Shinya Kitaoka 120a6e
// result) + " | Name",
Shinya Kitaoka 120a6e
// QString::fromStdString(name).left(70));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#ifdef USE_SQLITE_HDPOOL
Shinya Kitaoka 120a6e
      if (isHDActive()) m_hdPool->loadResourceInfos(result, resourcePath);
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      m_foundIterator = true;
Shinya Kitaoka 120a6e
      endCachedSearch();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      return result;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  endCachedSearch();
Shinya Kitaoka 120a6e
  return 0;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//----------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void TCacheResourcePool::releaseResource(TCacheResource *resource) {
Shinya Kitaoka 120a6e
  QMutexLocker locker(&m_memMutex);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Re-check the resource's reference count. This is necessary since a
Shinya Kitaoka 120a6e
  // concurrent
Shinya Kitaoka 120a6e
  // thread may have locked the memMutex for resource retrieval BEFORE this one.
Shinya Kitaoka 120a6e
  // If that is the case, the resource's refCount has increased back above 0.
Shinya Kitaoka 120a6e
  if (resource->m_refCount > 0) return;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#ifdef USE_SQLITE_HDPOOL
Shinya Kitaoka 120a6e
  QMutexLocker flushLocker(isHDActive() ? &m_hdPool->m_flushMutex : 0);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (isHDActive()) {
Shinya Kitaoka 120a6e
    // Flush all resource updates as this resource is being destroyed
Shinya Kitaoka 120a6e
    m_hdPool->flushResources();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    // Save the resource infos
Shinya Kitaoka 120a6e
    m_hdPool->saveResourceInfos(resource);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_memResources.erase(resource->m_pos);
Shinya Kitaoka 120a6e
  delete resource;
Toshihiro Shimizu 890ddd
}