Commit c855756d authored by Hugo Beauzée-Luyssen's avatar Hugo Beauzée-Luyssen
Browse files

Merge entity store back in SqliteTable helpers

parent 3fe1e17a
/*****************************************************************************
* Media Library
*****************************************************************************
* Copyright (C) 2015 Hugo Beauzée-Luyssen, Videolabs
*
* Authors: Hugo Beauzée-Luyssen<hugo@beauzee.fr>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#ifndef CACHE_H
#define CACHE_H
#include <cassert>
#include <memory>
#include <mutex>
#include <unordered_map>
#include "SqliteTools.h"
template <typename IMPL>
class Cache
{
using lock_t = std::unique_lock<std::recursive_mutex>;
public:
static lock_t lock()
{
return lock_t{ Mutex };
}
static std::shared_ptr<IMPL> load( unsigned int key )
{
auto it = Store.find( key );
if ( it == Store.end() )
return nullptr;
return it->second;
}
static void store( const std::shared_ptr<IMPL> value )
{
Store[value->id()] = value;
}
/**
* @brief discard Discard a record from the cache
*/
static bool discard( unsigned int key )
{
auto it = Store.find( key );
if ( it == Store.end() )
return false;
Store.erase( it );
return true;
}
static void clear()
{
Store.clear();
}
private:
static std::unordered_map<unsigned int, std::shared_ptr<IMPL>> Store;
static std::recursive_mutex Mutex;
};
template <typename IMPL>
std::unordered_map<unsigned int, std::shared_ptr<IMPL>>
Cache<IMPL>::Store;
template <typename IMPL>
std::recursive_mutex Cache<IMPL>::Mutex;
#endif // CACHE_H
......@@ -22,12 +22,18 @@
#pragma once
#include "Cache.h"
#include <memory>
#include <mutex>
#include <unordered_map>
#include <vector>
#include "Types.h"
#include "SqliteTools.h"
template <typename IMPL, typename TABLEPOLICY>
class Table
{
using _Cache = Cache<IMPL>;
using Lock = std::unique_lock<std::recursive_mutex>;
public:
template <typename... Args>
......@@ -52,52 +58,50 @@ class Table
static const std::string req = "SELECT * FROM " + TABLEPOLICY::Name;
// Lock the cache mutex before attempting to acquire a context, otherwise
// we could have a thread locking cache then DB, and a thread locking DB then cache
auto l = _Cache::lock();
Lock l{ Mutex };
return sqlite::Tools::fetchAll<IMPL, INTF>( dbConnection, req );
}
template <typename INTF, typename... Args>
static std::vector<std::shared_ptr<INTF>> fetchAll( DBConnection dbConnection, const std::string &req, Args&&... args )
{
auto l = _Cache::lock();
Lock l{ Mutex };
return sqlite::Tools::fetchAll<IMPL, INTF>( dbConnection, req, std::forward<Args>( args )... );
}
static std::shared_ptr<IMPL> load( DBConnection dbConnection, sqlite::Row& row )
{
auto l = _Cache::lock();
Lock l{ Mutex };
auto key = row.load<unsigned int>( 0 );
auto res = _Cache::load( key );
if ( res != nullptr )
return res;
res = std::make_shared<IMPL>( dbConnection, row );
_Cache::store( res );
auto it = Store.find( key );
if ( it != Store.end() )
return it->second;
auto res = std::make_shared<IMPL>( dbConnection, row );
Store[key] = res;
return res;
}
template <typename... Args>
static bool destroy( DBConnection dbConnection, unsigned int pkValue )
{
auto l = _Cache::lock();
Lock l{ Mutex };
static const std::string req = "DELETE FROM " + TABLEPOLICY::Name + " WHERE "
+ TABLEPOLICY::PrimaryKeyColumn + " = ?";
auto res = sqlite::Tools::executeDelete( dbConnection, req, pkValue );
if ( res == true )
_Cache::discard( pkValue );
else
{
// Simply ensure nothing was cached for this value if there's nothing to
// delete from DB
assert( _Cache::discard( pkValue ) == false );
auto it = Store.find( pkValue );
if ( it != end( Store ) )
Store.erase( it );
}
return res;
}
static void clear()
{
auto l = _Cache::lock();
_Cache::clear();
Lock l{ Mutex };
Store.clear();
}
protected:
......@@ -107,13 +111,26 @@ class Table
template <typename... Args>
static bool insert( DBConnection dbConnection, std::shared_ptr<IMPL> self, const std::string& req, Args&&... args )
{
auto l = _Cache::lock();
Lock l{ Mutex };
unsigned int pKey = sqlite::Tools::insert( dbConnection, req, std::forward<Args>( args )... );
if ( pKey == 0 )
return false;
(self.get())->*TABLEPOLICY::PrimaryKey = pKey;
_Cache::store( self );
assert( Store.find( pKey ) == end( Store ) );
Store[pKey] = self;
return true;
}
private:
static std::unordered_map<unsigned int, std::shared_ptr<IMPL>> Store;
static std::recursive_mutex Mutex;
};
template <typename IMPL, typename TABLEPOLICY>
std::unordered_map<unsigned int, std::shared_ptr<IMPL>>
Table<IMPL, TABLEPOLICY>::Store;
template <typename IMPL, typename TABLEPOLICY>
std::recursive_mutex Table<IMPL, TABLEPOLICY>::Mutex;
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment