Cache invalidation in Akonadi models

Somewhere hidden among the mass of words in my last blog entry I described an important drawback of using a single EntityTreeModel to lazily fetch and cache the Items in a tree, instead of fetching them anew each time.

The problem is knowing when to invalidate the cache. If no application is currently showing the contents of a Collection, there is no need for the Items in that Collection to be fetched, cached and kept up to date in the model. The effect we would like to achieve is to purge the Items in a Collection when those items are no longer shown anywhere in the application. Generally, that will mean that the Collection is not selected.

In Qt Model-View, the application data is stored in a model, and there may be one or more views attached to it displaying its contents. The model doesn’t have any knowledge of the views, and so it can’t know whether any particular Collection is selected, and purge its Iitems.

To solve this, I turned to the KSelectionProxyModel, which already has a lot of code for managing the selection a user makes in a view. By subclassing it, I was able to implement a reference counting system which increments the refcount of a Collection when it is selected, and decrements it when deselected. If the reference count of a Collection goes down to zero, it is put in a queue to be purged. It is not purged immediately, but queued because if the user is clicking around several Collection in a short time, we don’t want to purge the Collections each click or we’d lose the benefit of the caching. Like other similar optimisation techniques, this violates the object-oriented principle of modularity, but it is worth it for the benefit it brings. The effect can be seen in a customised version of our development tool akonadiconsole.

In the screenshots below I removed the filtering out of Items in the tree so that the fetching/purging can be seen. In real applications, the Items in the tree on the left would not be visible.

When a Collection is clicked, its Items are put into the model. The rest of the Collections have no items

When a Collection is clicked, its Items are put into the model. The rest of the Collections have no items

The Inbox Collection is selected, so its items are fetched. Personal Contacts is no longer selected, so it is put into a queue to be purged.

The Inbox Collection is selected, so its items are fetched. Personal Contacts is no longer selected, so it is put into a queue to be purged.

Select another Collection and its items are fetched too.

Select another Collection and its items are fetched too.

Another Collection is selected, pushing the Personal contacts out of the queue and purging them

Another Collection is selected, pushing the Personal contacts out of the queue and purging them

If the Collection is selected again, its Items are refetched

If the Collection is selected again, its Items are refetched

For this example, I used a queue length of just two Collections, so that if a Collection was deselected two clicks ago, it will be purged. In real applications, a longer queue length will be used, but it’s harder to illustrate in screenshots. Another unrealistic part of this demo is that this feature will like be used in applications like KMail where Collections can contain tens of thousands of Items and fetching them is an expensive operation.

This feature should be totally invisible to users and even developers using Akonadi, but it should offset the main disadvantage of using a cache of Items in the EntityTreeModel.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s


%d bloggers like this: