views:

250

answers:

3

Given that it's one of the hard things in computer science, does anyone know of a way to set up a plugable caching strategy?

What I'm thinking of would allow me to write a program with minimal thought as to what needs to be cached (e.i. use some sort of boiler-plate, low/no cost pattern that compiles away to nothing anywhere I might want caching) and then when things are further along and I know where I need caching I can add it in without making invasive code changes.

As an idea to the kind of solution I'm looking for; I'm working with the D programing language (but halfway sane C++ would be fine) and I like template.

+1  A: 

The nearest thing which comes to my mind is memoization for pure functions. Maybe also interesting for you might be this book Pattern Oriented Software Architecture Patterns Management which has caching pattern in it.

Gabriel Ščerbák
A: 

You may be interested in how Drizzle does this sort of thing with different storage and caching backends. In a nutshell, it provides an interface that can be used by a parent application to interact with MySQL, memcached, etc.

Nick Gerakines
That might be of interest, but I was thinking more along the lines of inside an application.
BCS
A: 

I'm not sure to which extent solution has to be "generalized" and "plugable", but if you can afford refactoring of usage of your caches (replacing function calls with direct use of some variable), then consider the following:

//works for any CopyConstructible type of cache and any function 
//which result should be cached 
//(the arguments of the function have to be properly binded)
/**
* caching + lazy initialization
* we shouldn't allow copying of lazy<T>, because every copy initializes its own cache
* and this is not what intended most of the time
* T must be CopyConstructible
*/
template<class T>
class lazy: private boost::noncopyable
{
public:
    lazy(boost::function0<T> _creator)
        : creator(_creator) {}
    /**
    * aka is_cashed
    */
    bool is_initialized()
    {
        return val;
    }
    operator T&()
    {
        if(!val)
            val = creator();
        return *val;
    }
    T& operator*()
    {
        if(!val)
            val = creator();
        return *val;
    }
    /**
    * resets cache to update it next time it is used
    */
    void reset()
    {
        val.reset();
    }
private:
    boost::function0<T> creator;
    boost::optional<T> val;
};
//usage
    //initialize caching and updating strategy
    lazy<WebPage> cached_page(boost::bind(&Server::getPage, server));
    server->OnPageUpdate = boost::bind(&OnPageUpdate, cached_page);
    .....

    //use cached_page everywhere as if it were regular variable of WebPage type
    showPage(cached_page);
//--------------
void OnPageUpdate(lazy<WebPage>& page)
{
    page.reset();
}

If you want to remove lazy initialization, then modify so that the cache is created in the constructor and method reset().

Alsk