unify .isyncuidmap.db handling with that of .uidvalidity
that is, open the database on demand when locking and close it again when unlocking.
This commit is contained in:
		
							parent
							
								
									4da89af7be
								
							
						
					
					
						commit
						5f265ad7da
					
				
					 2 changed files with 76 additions and 73 deletions
				
			
		
							
								
								
									
										5
									
								
								TODO
									
										
									
									
									
								
							
							
						
						
									
										5
									
								
								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 | ||||
|  |  | |||
|  | @ -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; | ||||
| 	} | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue