Camel.ViewSummary

The view summary manages the list of views. It exists as a separate object mainly so that both the store and the folder object can lookup details relevant to it.

Client code also has access to the view information, which contains a summary of folder information, for each view.

This is an abstract class, implementations must either implement it, or use Camel.ViewSummaryDisk, or Camel.ViewSummaryMem for their view summaries.

Basically the viewsummary is a persistent but passive table of view information to be used by an implementation to record details of each view.

Base class

The base class just has a size for each view record, and all of the virtual methods.

 struct _CamelViewSummaryClass {
        CamelObjectClass cobject_class;
 
        size_t view_sizeof;
 
        ... virtual methods ...
 };

Methods

Views can be looked up by view id. This is the complete folder + vid view id.

 CamelView *camel_view_summary_get(CamelViewSummary *s, const char *vid);

They can also be looked up using a search, i.e. to find all the views on a given folder. In this case the folder name is passed in root. Currently expr is not implemented. It returns an iterator which enumerates all of the views matching the root (and nominally, expr).

 CamelIterator *camel_view_summary_search(CamelViewSummary *s, const char *root, const char *expr, CamelException *ex);

Then there are management functions for creating, adding and removing views. These would be driven by the Evolution/CamelDS.FolderSummary for a given folder.

 void camel_view_summary_add(CamelViewSummary *s, CamelView *, CamelException *ex);
 void camel_view_summary_remove(CamelViewSummary *s, CamelView *);
 
 CamelView *camel_view_new(CamelViewSummary *, const char *vid);
 void camel_view_ref(CamelView *);
 void camel_view_unref(CamelView *);
 void camel_view_changed(CamelView *);

A final unref will trigger the virtual free method.

Camel.View

Each stored view is represented by a CamelView structure. It contains some summary information - message totals, and the rest is basically for managing them.

Implementations may sub-class this structure by adding additional fields following these.

 struct _CamelView {
        CamelViewSummary *summary;
 
        char *vid;
        char *expr;
 
        guint32 refcount:29;
        guint32 deleted:1;
        guint32 rebuild:1;
        guint32 changed:1;
 
        guint32 total_count;
        guint32 visible_count;
        guint32 unread_count;
        guint32 deleted_count;
        guint32 junk_count;
 };
  • vid: Consists of "folder name\01view id"
  • expr: The search expression used to match messages to this view. NULL for the root view.
  • deleted, rebuild, changed: Flags used to manage the implementation
  • *_count: Counts for messages in this view.

Camel.ViewSummaryMem

This is a concrete implementation which stores the view summary in memory. It could be used by purely online backends, those that do not need persistent state (e.g. pop), virtual stores, or those that store their information in some simple format (although it would make sense to subclass ViewSummary anyway).

Each view record is simply stored in memory and indexed using a GTree.

Camel.ViewSummaryDisk

This is a concrete implementation which stores each view in records of a libdb database, keyd by viewid. It also manages the in-memory copies of any views.

It serves another purpose as well, it stores a pointer to the per-store libdb database environment, and locking management. All libdb calls are serialised through this one lock - this avoid some races and deadlocks that are otherwise difficult or too inconvenient to avoid when using libdb.

Disk base class

The disk base class adds encode and decode virtual methods, for encoding and decoding each view record using a Evolution/CamelDS.Misc#Camel.Record object.

        void (*encode)(CamelViewSummaryDisk *, struct _CamelView *, struct _CamelRecordEncoder *);
        int (*decode)(CamelViewSummaryDisk *, struct _CamelView *, struct _CamelRecordDecoder *);

These are overriden (and inherited) if additional fields are added to the base Camel.View. The default implementation just stores the expression and counts.

Disk base object

This base object contains the store-wide database environment and management functions, and view caching information.

 struct _CamelViewSummaryDisk {
        CamelViewSummary summary;
 
        char *path;
 
        GMutex *lock;
        DB *views;
        DB_ENV *env;
 
        GHashTable *cache;
        GHashTable *changed;
 };
  • path: The path passed to db->env->open.

  • lock: A simple mutex which MUST be used to lock every call to libdb on this environment.
  • views: A table of all the views.
  • env: The environment.
  • cache, changed: Used to manage currently loaded and changed views, which must be written to disk.

The cache only contains currently-reffed views.

Methods

The construct methods take the libdb environment path.

 CamelViewSummaryDisk *camel_view_summary_disk_construct(CamelViewSummaryDisk *cvsd, const char *base, CamelException *ex);
 CamelViewSummaryDisk *camel_view_summary_disk_new(const char *base, CamelException *ex);

And there is a sync method which ensures any changed data is written securely to non-volatile storage.

 void camel_view_summary_disk_sync(CamelViewSummaryDisk *cds, CamelException *ex);

And finally there are locking macros. These should always be used to serialise access to any libdb calls on this environment, or any databases created from it.

 #define CVSD_LOCK_ENV(s) (g_mutex_lock(((CamelViewSummaryDisk *)s)->lock))
 #define CVSD_UNLOCK_ENV(s) (g_mutex_unlock(((CamelViewSummaryDisk *)s)->lock))

libdb environment

Currently, the libdb environment (which also covers all Evolution/CamelDS.FolderSummary databases!) is initialised using the following flags:

 DB_INIT_LOG|DB_INIT_MPOOL|DB_INIT_TXN|DB_CREATE|DB_RECOVER

These seem to create the most reliable database (TXN may not be required), although the archive logs are currently not automatically cleared in any way.

view table

The view table is a BTREE database. Each record is keyed on the full view-id.

The search function will use DB_SET when getting the first record, which means it will always run very quickly when getting the views of a specific folder.

Notes

If the CamelFolderInfo interfaces were removed from Evolution/Camel.Store, then this object probably wouldn't need to exist. Camel.View or its equivalent would still need to exist, but it could be rolled into the Evolution/CamelDS.FolderSummary. Database backend implementations could use other means of managing the store-global database state.

For the disk version, it may be possible to use a lock-per-table rather than enforcing a global environment lock. I didn't try this, as the per-environment lock seems to work well enough.

Also with the disk version, there must be some mechanism setup to automatically delete old archive logs. A libdb upgrade does provide such a feature, although it should be relatively simple to implement it using the current version.

Apps/Evolution/CamelDS.ViewSummary (last edited 2013-08-08 22:50:01 by WilliamJonMcCann)