BCS
BCS

Reputation: 78683

Generalized plugable caching pattern?

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.

Upvotes: 8

Views: 1190

Answers (4)

Dmitry Ledentsov
Dmitry Ledentsov

Reputation: 3660

there's a c++0x solution to generic automatic memoization (see answer here: What are reasonable ways to improve solving recursive problems? )

Upvotes: 1

Alsk
Alsk

Reputation: 1118

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().

Upvotes: 0

Nick Gerakines
Nick Gerakines

Reputation: 1450

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.

Upvotes: 0

Gabriel Ščerb&#225;k
Gabriel Ščerb&#225;k

Reputation: 18580

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.

Upvotes: 1

Related Questions