commit 5f265ad7dabbd3fd7eb22408942c4502a5162184
Author: Oswald Buddenhagen <[email protected]>
Date:   Thu Jan 1 19:25:17 2015 +0100

    unify .isyncuidmap.db handling with that of .uidvalidity
    
    that is, open the database on demand when locking and close it again
    when unlocking.

 TODO              |    5 --
 src/drv_maildir.c |  144 ++++++++++++++++++++++++---------------------
 2 files changed, 76 insertions(+), 73 deletions(-)

diff --git a/TODO b/TODO
index ec1cf2e..0888b65 100644
--- a/TODO
+++ b/TODO
@@ -18,11 +18,6 @@ add alternative treatments of expired messages. 
ExpiredMessageMode: Prune
 (delete messages like now), Keep (just don't sync) and Archive (move to
 separate folder - ArchiveSuffix, default .archive).
 
-unify maildir locking between the two UID storage schemes.
-re-opening the db may be expensive, so keep it open.
-but keeping lock for too long (e.g., big message downloads) may block other
-clients. auto-release lock after 500 ms?
-
 kill the concept of an INBOX, it is a relic from single-channel operation.
 if somebody needs it, he can have two stores with different Paths. the path
 can name a single (in-)box (curr. broken with maildir). an empty box name
diff --git a/src/drv_maildir.c b/src/drv_maildir.c
index 117e623..85313df 100644
--- a/src/drv_maildir.c
+++ b/src/drv_maildir.c
@@ -73,6 +73,7 @@ typedef struct maildir_store {
        char *trash;
 #ifdef USE_DB
        DB *db;
+       char *usedb;
 #endif /* USE_DB */
        wakeup_t lcktmr;
 } maildir_store_t;
@@ -184,6 +185,7 @@ maildir_cleanup( store_t *gctx )
 #ifdef USE_DB
        if (ctx->db)
                ctx->db->close( ctx->db, 0 );
+       free( ctx->usedb );
 #endif /* USE_DB */
        free( gctx->path );
        free( ctx->excs );
@@ -518,6 +520,10 @@ static int
 maildir_uidval_lock( maildir_store_t *ctx )
 {
        int n;
+#ifdef USE_DB
+       int ret;
+       struct stat st;
+#endif
        char buf[128];
 
        if (ctx->lcktmr.links.next) {
@@ -541,21 +547,52 @@ maildir_uidval_lock( maildir_store_t *ctx )
                error( "Maildir error: cannot fcntl lock UIDVALIDITY.\n" );
                return DRV_BOX_BAD;
        }
-       lseek( ctx->uvfd, 0, SEEK_SET );
-       if ((n = read( ctx->uvfd, buf, sizeof(buf) - 1 )) <= 0 ||
-           (buf[n] = 0, sscanf( buf, "%d\n%d", &ctx->gen.uidvalidity, 
&ctx->nuid ) != 2)) {
-#if 1
-               /* In a generic driver, resetting the UID validity would be the 
right thing.
-                * But this would mess up the sync state completely. So better 
bail out and
-                * give the user a chance to fix the mailbox. */
-               if (n) {
-                       error( "Maildir error: cannot read UIDVALIDITY.\n" );
+
+#ifdef USE_DB
+       if (ctx->usedb) {
+               if (fstat( ctx->uvfd, &st )) {
+                       sys_error( "Maildir error: cannot fstat UID database" );
                        return DRV_BOX_BAD;
                }
-#endif
-               return maildir_init_uidval_new( ctx );
+               if (db_create( &ctx->db, 0, 0 )) {
+                       fputs( "Maildir error: db_create() failed\n", stderr );
+                       return DRV_BOX_BAD;
+               }
+               if ((ret = (ctx->db->open)( ctx->db, 0, ctx->usedb, 0, DB_HASH,
+                                           st.st_size ? 0 : DB_CREATE | 
DB_TRUNCATE, 0 ))) {
+                       ctx->db->err( ctx->db, ret, "Maildir error: 
db->open(%s)", ctx->usedb );
+                       return DRV_BOX_BAD;
+               }
+               key.data = (void *)"UIDVALIDITY";
+               key.size = 11;
+               if ((ret = ctx->db->get( ctx->db, 0, &key, &value, 0 ))) {
+                       if (ret != DB_NOTFOUND) {
+                               ctx->db->err( ctx->db, ret, "Maildir error: 
db->get()" );
+                               return DRV_BOX_BAD;
+                       }
+                       return maildir_init_uidval_new( ctx );
+               }
+               ctx->gen.uidvalidity = ((int *)value.data)[0];
+               ctx->nuid = ((int *)value.data)[1];
        } else
-               ctx->uvok = 1;
+#endif
+       {
+               lseek( ctx->uvfd, 0, SEEK_SET );
+               if ((n = read( ctx->uvfd, buf, sizeof(buf) - 1 )) <= 0 ||
+                       (buf[n] = 0, sscanf( buf, "%d\n%d", 
&ctx->gen.uidvalidity, &ctx->nuid ) != 2)) {
+#if 1
+                       /* In a generic driver, resetting the UID validity 
would be the right thing.
+                        * But this would mess up the sync state completely. So 
better bail out and
+                        * give the user a chance to fix the mailbox. */
+                       if (n) {
+                               error( "Maildir error: cannot read 
UIDVALIDITY.\n" );
+                               return DRV_BOX_BAD;
+                       }
+#endif
+                       return maildir_init_uidval_new( ctx );
+               }
+       }
+       ctx->uvok = 1;
        conf_wakeup( &ctx->lcktmr, 2 );
        return DRV_OK;
 }
@@ -563,6 +600,12 @@ maildir_uidval_lock( maildir_store_t *ctx )
 static void
 maildir_uidval_unlock( maildir_store_t *ctx )
 {
+#ifdef USE_DB
+       if (ctx->db) {
+               ctx->db->close( ctx->db, 0 );
+               ctx->db = 0;
+       }
+#endif /* USE_DB */
        lck.l_type = F_UNLCK;
        fcntl( ctx->uvfd, F_SETLK, &lck );
 #ifdef LEGACY_FLOCK
@@ -594,6 +637,8 @@ maildir_set_uid( maildir_store_t *ctx, const char *name, 
int *uid )
 {
        int ret;
 
+       if ((ret = maildir_uidval_lock( ctx )) != DRV_OK)
+               return ret;
        *uid = ++ctx->nuid;
 
        make_key( ((maildir_store_conf_t *)ctx->gen.conf)->info_stop, &key, 
(char *)name );
@@ -693,7 +738,7 @@ maildir_scan( maildir_store_t *ctx, msglist_t *msglist )
        ctx->gen.count = ctx->gen.recent = 0;
        if (ctx->uvok || ctx->maxuid == INT_MAX) {
 #ifdef USE_DB
-               if (ctx->db) {
+               if (ctx->usedb) {
                        if (db_create( &tdb, 0, 0 )) {
                                fputs( "Maildir error: db_create() failed\n", 
stderr );
                                return DRV_BOX_BAD;
@@ -734,7 +779,7 @@ maildir_scan( maildir_store_t *ctx, msglist_t *msglist )
                                maildir_free_scan( msglist );
                          dfail:
 #ifdef USE_DB
-                               if (ctx->db)
+                               if (ctx->usedb)
                                        tdb->close( tdb, 0 );
 #endif /* USE_DB */
                                return DRV_BOX_BAD;
@@ -745,7 +790,9 @@ maildir_scan( maildir_store_t *ctx, msglist_t *msglist )
                                ctx->gen.count++;
                                ctx->gen.recent += i;
 #ifdef USE_DB
-                               if (ctx->db) {
+                               if (ctx->usedb) {
+                                       if (maildir_uidval_lock( ctx ) != 
DRV_OK)
+                                               goto mbork;
                                        make_key( conf->info_stop, &key, 
e->d_name );
                                        if ((ret = ctx->db->get( ctx->db, 0, 
&key, &value, 0 ))) {
                                                if (ret != DB_NOTFOUND) {
@@ -802,7 +849,7 @@ maildir_scan( maildir_store_t *ctx, msglist_t *msglist )
                        if (st.st_mtime != stamps[i]) {
                                /* Somebody messed with the mailbox since we 
started listing it. */
 #ifdef USE_DB
-                               if (ctx->db)
+                               if (ctx->usedb)
                                        tdb->close( tdb, 0 );
 #endif /* USE_DB */
                                maildir_free_scan( msglist );
@@ -810,8 +857,10 @@ maildir_scan( maildir_store_t *ctx, msglist_t *msglist )
                        }
                }
 #ifdef USE_DB
-               if (ctx->db) {
-                       if ((ret = ctx->db->cursor( ctx->db, 0, &dbc, 0 )))
+               if (ctx->usedb) {
+                       if (maildir_uidval_lock( ctx ) != DRV_OK)
+                               ;
+                       else if ((ret = ctx->db->cursor( ctx->db, 0, &dbc, 0 )))
                                ctx->db->err( ctx->db, ret, "Maildir error: 
db->cursor()" );
                        else {
                                for (;;) {
@@ -868,7 +917,7 @@ maildir_scan( maildir_store_t *ctx, msglist_t *msglist )
                                if ((ctx->gen.opts & OPEN_SIZE) || 
((ctx->gen.opts & OPEN_FIND) && uid >= ctx->newuid))
                                        nfsnprintf( buf + bl, sizeof(buf) - bl, 
"%s/%s", subdirs[entry->recent], entry->base );
 #ifdef USE_DB
-                       } else if (ctx->db) {
+                       } else if (ctx->usedb) {
                                if ((ret = maildir_set_uid( ctx, entry->base, 
&uid )) != DRV_OK) {
                                        maildir_free_scan( msglist );
                                        return ret;
@@ -982,6 +1031,7 @@ maildir_select_box( store_t *gctx, const char *name )
        ctx->uvfd = -1;
 #ifdef USE_DB
        ctx->db = 0;
+       ctx->usedb = 0;
 #endif /* USE_DB */
        ctx->fresh[0] = ctx->fresh[1] = 0;
        if (starts_with( name, -1, "INBOX", 5 ) && (!name[5] || name[5] == 
'/')) {
@@ -1002,9 +1052,6 @@ maildir_open_box( store_t *gctx,
 {
        maildir_store_t *ctx = (maildir_store_t *)gctx;
        int ret;
-#ifdef USE_DB
-       struct stat st;
-#endif /* USE_DB */
        char uvpath[_POSIX_PATH_MAX];
 
        if ((ret = maildir_validate( gctx->path, 0, ctx )) != DRV_OK)
@@ -1018,6 +1065,7 @@ maildir_open_box( store_t *gctx,
                return;
        }
 #else
+       ctx->usedb = 0;
        if ((ctx->uvfd = open( uvpath, O_RDWR, 0600 )) < 0) {
                nfsnprintf( uvpath, sizeof(uvpath), "%s/.isyncuidmap.db", 
gctx->path );
                if ((ctx->uvfd = open( uvpath, O_RDWR, 0600 )) < 0) {
@@ -1032,52 +1080,10 @@ maildir_open_box( store_t *gctx,
                        sys_error( "Maildir error: cannot write %s", uvpath );
                        cb( DRV_BOX_BAD, aux );
                        return;
-               }
-         dbok:
-#if SEEK_SET != 0
-               lck.l_whence = SEEK_SET;
-#endif
-               lck.l_type = F_WRLCK;
-               if (fcntl( ctx->uvfd, F_SETLKW, &lck )) {
-                       sys_error( "Maildir error: cannot lock %s", uvpath );
-                       cb( DRV_BOX_BAD, aux );
-                       return;
-               }
-               if (fstat( ctx->uvfd, &st )) {
-                       sys_error( "Maildir error: cannot stat %s", uvpath );
-                       cb( DRV_BOX_BAD, aux );
-                       return;
-               }
-               if (db_create( &ctx->db, 0, 0 )) {
-                       fputs( "Maildir error: db_create() failed\n", stderr );
-                       cb( DRV_BOX_BAD, aux );
-                       return;
-               }
-               if ((ret = (ctx->db->open)( ctx->db, 0, uvpath, 0, DB_HASH,
-                                           st.st_size ? 0 : DB_CREATE | 
DB_TRUNCATE, 0 ))) {
-                       ctx->db->err( ctx->db, ret, "Maildir error: 
db->open(%s)", uvpath );
-                       cb( DRV_BOX_BAD, aux );
-                       return;
-               }
-               key.data = (void *)"UIDVALIDITY";
-               key.size = 11;
-               if ((ret = ctx->db->get( ctx->db, 0, &key, &value, 0 ))) {
-                       if (ret != DB_NOTFOUND) {
-                               ctx->db->err( ctx->db, ret, "Maildir error: 
db->get()" );
-                               cb( DRV_BOX_BAD, aux );
-                               return;
-                       }
-                       if (maildir_init_uidval_new( ctx ) != DRV_OK) {
-                               cb( DRV_BOX_BAD, aux );
-                               return;
-                       }
                } else {
-                       ctx->gen.uidvalidity = ((int *)value.data)[0];
-                       ctx->nuid = ((int *)value.data)[1];
-                       ctx->uvok = 1;
+                 dbok:
+                       ctx->usedb = nfstrdup( uvpath );
                }
-               cb( DRV_OK, aux );
-               return;
        }
   fnok:
 #endif /* USE_DB */
@@ -1327,7 +1333,7 @@ maildir_store_msg( store_t *gctx, msg_data_t *data, int 
to_trash,
        bl = nfsnprintf( base, sizeof(base), "%ld.%d_%d.%s", (long)time( 0 ), 
Pid, ++MaildirCount, Hostname );
        if (!to_trash) {
 #ifdef USE_DB
-               if (ctx->db) {
+               if (ctx->usedb) {
                        if ((ret = maildir_set_uid( ctx, base, &uid )) != 
DRV_OK) {
                                free( data->data );
                                cb( ret, 0, aux );
@@ -1480,6 +1486,8 @@ maildir_purge_msg( maildir_store_t *ctx, const char *name 
)
 {
        int ret;
 
+       if ((ret = maildir_uidval_lock( ctx )) != DRV_OK)
+               return ret;
        make_key( ((maildir_store_conf_t *)ctx->gen.conf)->info_stop, &key, 
(char *)name );
        if ((ret = ctx->db->del( ctx->db, 0, &key, 0 ))) {
                ctx->db->err( ctx->db, ret, "Maildir error: db->del()" );
@@ -1529,7 +1537,7 @@ maildir_trash_msg( store_t *gctx, message_t *gmsg,
        gctx->count--;
 
 #ifdef USE_DB
-       if (ctx->db) {
+       if (ctx->usedb) {
                cb( maildir_purge_msg( ctx, msg->base ), aux );
                return;
        }

------------------------------------------------------------------------------
New Year. New Location. New Benefits. New Data Center in Ashburn, VA.
GigeNET is offering a free month of service with a new server in Ashburn.
Choose from 2 high performing configs, both with 100TB of bandwidth.
Higher redundancy.Lower latency.Increased capacity.Completely compliant.
http://p.sf.net/sfu/gigenet
_______________________________________________
isync-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/isync-devel

Reply via email to