[dovecot-cvs] dovecot/src/plugins/acl acl-api-private.h, 1.1, 1.2 acl-api.c, 1.1, 1.2 acl-backend-vfile.c, 1.1, 1.2 acl-backend.c, 1.1, 1.2 acl-cache.c, 1.1, 1.2 acl-cache.h, 1.1, 1.2 acl-storage.c, 1.1, 1.2

tss-movial at dovecot.org tss-movial at dovecot.org
Tue Feb 28 14:38:24 EET 2006


Update of /var/lib/cvs/dovecot/src/plugins/acl
In directory talvi:/tmp/cvs-serv32291/plugins/acl

Modified Files:
	acl-api-private.h acl-api.c acl-backend-vfile.c acl-backend.c 
	acl-cache.c acl-cache.h acl-storage.c 
Log Message:
Don't keep acl_objects permanently in memory. Moved cache validity information into cache records. Some other cleanups and fixes.



Index: acl-api-private.h
===================================================================
RCS file: /var/lib/cvs/dovecot/src/plugins/acl/acl-api-private.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- acl-api-private.h	27 Feb 2006 16:30:39 -0000	1.1
+++ acl-api-private.h	28 Feb 2006 12:38:20 -0000	1.2
@@ -33,13 +33,10 @@
 	struct acl_cache *cache;
 	struct acl_mask *default_rights;
 
-	struct hash_table *aclobjs;
 	struct acl_backend_vfuncs v;
 };
 
 struct acl_object {
-	int refcount;
-
 	struct acl_backend *backend;
 	char *name;
 };

Index: acl-api.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/plugins/acl/acl-api.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- acl-api.c	27 Feb 2006 16:30:39 -0000	1.1
+++ acl-api.c	28 Feb 2006 12:38:20 -0000	1.2
@@ -9,23 +9,10 @@
 struct acl_object *acl_object_init_from_name(struct acl_backend *backend,
 					     const char *name)
 {
-	struct acl_object *aclobj;
-	const char *control_dir;
-
-	aclobj = hash_lookup(backend->aclobjs, name);
-	if (aclobj != NULL) {
-		i_assert(aclobj->refcount >= 0);
-		aclobj->refcount++;
-		return aclobj;
-	}
-
-	control_dir =
+	const char *control_dir =
 		mail_storage_get_mailbox_control_dir(backend->storage, name);
 
-	aclobj = backend->v.object_init(backend, name, control_dir);
-	aclobj->refcount++;
-	hash_insert(backend->aclobjs, aclobj->name, aclobj);
-	return aclobj;
+	return backend->v.object_init(backend, name, control_dir);
 }
 
 struct acl_object *acl_object_init_from_mailbox(struct acl_backend *backend,
@@ -40,14 +27,8 @@
 {
 	struct acl_object *aclobj = *_aclobj;
 
-	i_assert(aclobj->refcount > 0);
-
 	*_aclobj = NULL;
-	if (--aclobj->refcount > 0)
-		return;
-
-	/* currently ACL objects are really freed only at backend
-	   deinitialization. */
+	aclobj->backend->v.object_deinit(aclobj);
 }
 
 int acl_object_have_right(struct acl_object *aclobj, unsigned int right_idx)

Index: acl-backend-vfile.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/plugins/acl/acl-backend-vfile.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- acl-backend-vfile.c	27 Feb 2006 16:30:39 -0000	1.1
+++ acl-backend-vfile.c	28 Feb 2006 12:38:20 -0000	1.2
@@ -18,14 +18,16 @@
 #define ACL_SYNC_SECS 1
 #define ACL_ESTALE_RETRY_COUNT NFS_ESTALE_RETRY_COUNT
 
-struct acl_vfile {
-	char *path;
-
+struct acl_vfile_validity {
 	time_t last_read_time;
 	time_t last_mtime;
 	off_t last_size;
 };
 
+struct acl_backend_vfile_validity {
+	struct acl_vfile_validity global_validity, local_validity;
+};
+
 struct acl_backend_vfile {
 	struct acl_backend backend;
 	const char *global_dir;
@@ -34,7 +36,7 @@
 struct acl_object_vfile {
 	struct acl_object aclobj;
 
-	struct acl_vfile global_file, local_file;
+	char *global_path, *local_path;
 };
 
 struct acl_letter_map {
@@ -65,6 +67,9 @@
 	backend = p_new(pool, struct acl_backend_vfile, 1);
 	backend->global_dir = p_strdup(pool, data);
 	backend->backend.pool = pool;
+	backend->backend.cache =
+		acl_cache_init(&backend->backend,
+			       sizeof(struct acl_backend_vfile_validity));
 	return &backend->backend;
 }
 
@@ -84,9 +89,9 @@
 	aclobj = i_new(struct acl_object_vfile, 1);
 	aclobj->aclobj.backend = _backend;
 	aclobj->aclobj.name = i_strdup(name);
-	aclobj->global_file.path =
+	aclobj->global_path =
 		i_strconcat(backend->global_dir, "/", name, NULL);
-	aclobj->local_file.path =
+	aclobj->local_path =
 		i_strconcat(control_dir, "/"ACL_FILENAME, NULL);
 	return &aclobj->aclobj;
 }
@@ -95,8 +100,8 @@
 {
 	struct acl_object_vfile *aclobj = (struct acl_object_vfile *)_aclobj;
 
-	i_free(aclobj->local_file.path);
-	i_free(aclobj->global_file.path);
+	i_free(aclobj->local_path);
+	i_free(aclobj->global_path);
 	i_free(aclobj->aclobj.name);
 	i_free(aclobj);
 }
@@ -143,7 +148,7 @@
 }
 
 static int
-acl_object_vfile_parse_line(struct acl_object *aclobj, struct acl_vfile *file,
+acl_object_vfile_parse_line(struct acl_object *aclobj, const char *path,
 			    const char *line, unsigned int linenum)
 {
 	struct acl_rights rights;
@@ -198,7 +203,7 @@
 	if (error != NULL) {
 		mail_storage_set_critical(aclobj->backend->storage,
 					  "ACL file %s line %u: %s",
-					  file->path, linenum, error);
+					  path, linenum, error);
 		t_pop();
 		return -1;
 	}
@@ -210,8 +215,8 @@
 }
 
 static int
-acl_backend_vfile_read(struct acl_object *aclobj, struct acl_vfile *file,
-		       bool try_retry)
+acl_backend_vfile_read(struct acl_object *aclobj, const char *path,
+		       struct acl_vfile_validity *validity, bool try_retry)
 {
 	struct mail_storage *storage = aclobj->backend->storage;
 	struct istream *input;
@@ -220,21 +225,22 @@
 	unsigned int linenum;
 	int fd, ret = 1;
 
-	fd = nfs_safe_open(file->path, O_RDONLY);
+	fd = nfs_safe_open(path, O_RDONLY);
 	if (fd == -1) {
 		if (errno == ENOENT) {
-			file->last_read_time = ioloop_time;
+			validity->last_size = 0;
+			validity->last_mtime = 0;
+			validity->last_read_time = ioloop_time;
 			return 1;
 		}
-		mail_storage_set_critical(storage,
-					  "open(%s) failed: %m", file->path);
+		mail_storage_set_critical(storage, "open(%s) failed: %m", path);
 		return -1;
 	}
 	input = i_stream_create_file(fd, default_pool, 4096, FALSE);
 
 	linenum = 1;
 	while ((line = i_stream_read_next_line(input)) != NULL) {
-		if (acl_object_vfile_parse_line(aclobj, file, line,
+		if (acl_object_vfile_parse_line(aclobj, path, line,
 						linenum++) < 0) {
 			ret = -1;
 			break;
@@ -247,7 +253,7 @@
 		else {
 			ret = -1;
 			mail_storage_set_critical(storage,
-				"read(%s) failed: %m", file->path);
+						  "read(%s) failed: %m", path);
 		}
 	}
 
@@ -258,12 +264,12 @@
 			else {
 				ret = -1;
 				mail_storage_set_critical(storage,
-					"read(%s) failed: %m", file->path);
+					"read(%s) failed: %m", path);
 			}
 		} else {
-			file->last_read_time = ioloop_time;
-			file->last_mtime = st.st_mtime;
-			file->last_size = st.st_size;
+			validity->last_read_time = ioloop_time;
+			validity->last_mtime = st.st_mtime;
+			validity->last_size = st.st_size;
 		}
 	}
 
@@ -273,21 +279,21 @@
 			return 0;
 
 		mail_storage_set_critical(storage, "close(%s) failed: %m",
-					  file->path);
+					  path);
 		return -1;
 	}
 	return ret;
 }
 
 static int
-acl_backend_vfile_read_with_retry(struct acl_object *aclobj,
-				  struct acl_vfile *file)
+acl_backend_vfile_read_with_retry(struct acl_object *aclobj, const char *path,
+				  struct acl_vfile_validity *validity)
 {
 	unsigned int i;
 	int ret;
 
 	for (i = 0;; i++) {
-		ret = acl_backend_vfile_read(aclobj, file,
+		ret = acl_backend_vfile_read(aclobj, path, validity,
 					     i < ACL_ESTALE_RETRY_COUNT);
 		if (ret != 0)
 			break;
@@ -299,32 +305,33 @@
 }
 
 static int
-acl_backend_vfile_refresh(struct acl_object *aclobj, struct acl_vfile *file)
+acl_backend_vfile_refresh(struct acl_object *aclobj, const char *path,
+			  const struct acl_vfile_validity *validity)
 {
 	struct stat st;
 
-	if (file->last_read_time == 0)
+	if (validity == NULL)
 		return 1;
 
-	if (stat(file->path, &st) < 0) {
+	if (stat(path, &st) < 0) {
 		if (errno == ENOENT) {
-			/* No global ACL directory */
-			return 0;
-		}
+			/* if the file used to exist, we have to re-read it */
+			return validity->last_mtime != 0;
+		} 
 		mail_storage_set_critical(aclobj->backend->storage,
-					  "stat(%s) failed: %m", file->path);
+					  "stat(%s) failed: %m", path);
 		return -1;
 	}
 
-	if (st.st_mtime == file->last_mtime &&
-	    st.st_size == file->last_size) {
+	if (st.st_mtime == validity->last_mtime &&
+	    st.st_size == validity->last_size) {
 		/* same timestamp, but if it was modified within the
 		   same second we want to refresh it again later (but
 		   do it only after a couple of seconds so we don't
 		   keep re-reading it all the time within those
 		   seconds) */
-		if (st.st_mtime < file->last_read_time - ACL_SYNC_SECS ||
-		    ioloop_time - file->last_read_time <= ACL_SYNC_SECS)
+		if (st.st_mtime < validity->last_read_time - ACL_SYNC_SECS ||
+		    ioloop_time - validity->last_read_time <= ACL_SYNC_SECS)
 			return 0;
 	}
 
@@ -334,21 +341,36 @@
 static int acl_backend_vfile_object_refresh_cache(struct acl_object *_aclobj)
 {
 	struct acl_object_vfile *aclobj = (struct acl_object_vfile *)_aclobj;
+	const struct acl_backend_vfile_validity *old_validity;
+	struct acl_backend_vfile_validity validity;
 	int ret;
 
-	ret = acl_backend_vfile_refresh(_aclobj, &aclobj->global_file);
-	if (ret == 0)
-		ret = acl_backend_vfile_refresh(_aclobj, &aclobj->local_file);
+	old_validity = acl_cache_get_validity(_aclobj->backend->cache,
+					      _aclobj->name);
+	ret = acl_backend_vfile_refresh(_aclobj, aclobj->global_path,
+					old_validity == NULL ? NULL :
+					&old_validity->global_validity);
+	if (ret == 0) {
+		ret = acl_backend_vfile_refresh(_aclobj, aclobj->local_path,
+						old_validity == NULL ? NULL :
+						&old_validity->local_validity);
+	}
 	if (ret <= 0)
 		return ret;
 
 	/* either global or local ACLs changed, need to re-read both */
 	acl_cache_flush(_aclobj->backend->cache, _aclobj->name);
-	if (acl_backend_vfile_read_with_retry(_aclobj,
-					      &aclobj->global_file) < 0)
+
+	memset(&validity, 0, sizeof(validity));
+	if (acl_backend_vfile_read_with_retry(_aclobj, aclobj->global_path,
+					      &validity.global_validity) < 0)
 		return -1;
-	if (acl_backend_vfile_read_with_retry(_aclobj, &aclobj->local_file) < 0)
+	if (acl_backend_vfile_read_with_retry(_aclobj, aclobj->local_path,
+					      &validity.local_validity) < 0)
 		return -1;
+
+	acl_cache_set_validity(_aclobj->backend->cache,
+			       _aclobj->name, &validity);
 	return 0;
 }
 

Index: acl-backend.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/plugins/acl/acl-backend.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- acl-backend.c	27 Feb 2006 16:30:39 -0000	1.1
+++ acl-backend.c	28 Feb 2006 12:38:20 -0000	1.2
@@ -46,9 +46,6 @@
 	backend->username = p_strdup(backend->pool, acl_username);
 	backend->owner_username = p_strdup(backend->pool, owner_username);
 	backend->group_count = group_count;
-	backend->cache = acl_cache_init(backend);
-	backend->aclobjs = hash_create(default_pool, backend->pool, 0,
-				       str_hash, (hash_cmp_callback_t *)strcmp);
 
 	storage_owner = owner_username != NULL &&
 		strcmp(acl_username, owner_username) == 0;
@@ -71,21 +68,10 @@
 void acl_backend_deinit(struct acl_backend **_backend)
 {
 	struct acl_backend *backend = *_backend;
-	struct hash_iterate_context *iter;
-	void *key, *value;
 
 	*_backend = NULL;
 
-	iter = hash_iterate_init(backend->aclobjs);
-	while (hash_iterate(iter, &key, &value)) {
-		struct acl_object *aclobj = value;
-
-		aclobj->backend->v.object_deinit(aclobj);
-	}
-	hash_iterate_deinit(iter);
-
 	acl_cache_deinit(&backend->cache);
-	hash_destroy(backend->aclobjs);
 	backend->v.deinit(backend);
 }
 

Index: acl-cache.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/plugins/acl/acl-cache.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- acl-cache.c	27 Feb 2006 16:30:39 -0000	1.1
+++ acl-cache.c	28 Feb 2006 12:38:20 -0000	1.2
@@ -24,6 +24,8 @@
 	struct acl_backend *backend;
 	struct hash_table *objects; /* name => struct acl_object_cache* */
 
+	size_t validity_rec_size;
+
 	/* Right names mapping is used for faster rights checking. Note that
 	   acl_mask bitmask relies on the order to never change, so only new
 	   rights can be added to the mapping. */
@@ -34,12 +36,16 @@
 	struct hash_table *right_name_idx_map;
 };
 
-struct acl_cache *acl_cache_init(struct acl_backend *backend)
+static struct acl_mask negative_cache_entry;
+
+struct acl_cache *acl_cache_init(struct acl_backend *backend,
+				 size_t validity_rec_size)
 {
 	struct acl_cache *cache;
 
 	cache = i_new(struct acl_cache, 1);
 	cache->backend = backend;
+	cache->validity_rec_size = validity_rec_size;
 	cache->right_names_pool =
 		pool_alloconly_create("ACL right names", 1024);
 	cache->objects = hash_create(default_pool, default_pool, 0,
@@ -120,16 +126,17 @@
 	unsigned int idx;
 	void *idx_p;
 	char *name;
+	const char *const_name;
 
 	/* use +1 for right_name_idx_map values because we can't add NULL
 	   values. */
 	idx_p = hash_lookup(cache->right_name_idx_map, right);
 	if (idx_p == NULL) {
 		/* new right name, add it */
-		name = p_strdup(cache->right_names_pool, right);
+		const_name = name = p_strdup(cache->right_names_pool, right);
 
 		idx = array_count(&cache->right_idx_name_map);
-		array_append(&cache->right_idx_name_map, &name, 1);
+		array_append(&cache->right_idx_name_map, &const_name, 1);
 		hash_insert(cache->right_name_idx_map, name,
 			    POINTER_CAST(idx + 1));
 	} else {
@@ -253,17 +260,33 @@
 				     &obj_cache->my_neg_rights[id_type]);
 }
 
-void acl_cache_update(struct acl_cache *cache, const char *objname,
-		      const struct acl_rights *rights)
+static struct acl_object_cache *
+acl_cache_object_get(struct acl_cache *cache, const char *objname,
+		     bool *created_r)
 {
 	struct acl_object_cache *obj_cache;
 
 	obj_cache = hash_lookup(cache->objects, objname);
 	if (obj_cache == NULL) {
-		obj_cache = i_new(struct acl_object_cache, 1);
+		obj_cache = i_malloc(sizeof(struct acl_object_cache) +
+				     cache->validity_rec_size);
 		obj_cache->name = i_strdup(objname);
 		hash_insert(cache->objects, obj_cache->name, obj_cache);
+		*created_r = TRUE;
+	} else {
+		*created_r = FALSE;
 	}
+	return obj_cache;
+}
+
+void acl_cache_update(struct acl_cache *cache, const char *objname,
+		      const struct acl_rights *rights)
+{
+	struct acl_object_cache *obj_cache;
+	bool created;
+
+	obj_cache = acl_cache_object_get(cache, objname, &created);
+	i_assert(obj_cache->my_current_rights != &negative_cache_entry);
 
 	switch (rights->id_type) {
 	case ACL_ID_ANYONE:
@@ -289,6 +312,32 @@
 	}
 }
 
+void acl_cache_set_validity(struct acl_cache *cache, const char *objname,
+			    const void *validity)
+{
+	struct acl_object_cache *obj_cache;
+	bool created;
+
+	obj_cache = acl_cache_object_get(cache, objname, &created);
+
+	/* @UNSAFE: validity is stored after the cache record */
+	memcpy(obj_cache + 1, validity, cache->validity_rec_size);
+
+	if (created) {
+		/* negative cache entry */
+		obj_cache->my_current_rights = &negative_cache_entry;
+	} 
+}
+
+const void *acl_cache_get_validity(struct acl_cache *cache,
+				   const char *objname)
+{
+	struct acl_object_cache *obj_cache;
+
+	obj_cache = hash_lookup(cache->objects, objname);
+	return obj_cache == NULL ? NULL : (obj_cache + 1);
+}
+
 const char *const *acl_cache_get_names(struct acl_cache *cache,
 				       unsigned int *count_r)
 {
@@ -343,7 +392,8 @@
 	struct acl_object_cache *obj_cache;
 
 	obj_cache = hash_lookup(cache->objects, objname);
-	if (obj_cache == NULL)
+	if (obj_cache == NULL ||
+	    obj_cache->my_current_rights == &negative_cache_entry)
 		return NULL;
 
 	if (obj_cache->my_current_rights == NULL)

Index: acl-cache.h
===================================================================
RCS file: /var/lib/cvs/dovecot/src/plugins/acl/acl-cache.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- acl-cache.h	27 Feb 2006 16:30:39 -0000	1.1
+++ acl-cache.h	28 Feb 2006 12:38:20 -0000	1.2
@@ -17,7 +17,8 @@
 	(sizeof(pool_t) + sizeof(unsigned int) + \
 	 (count + CHAR_BIT-1) / CHAR_BIT)
 
-struct acl_cache *acl_cache_init(struct acl_backend *backend);
+struct acl_cache *acl_cache_init(struct acl_backend *backend,
+				 size_t validity_rec_size);
 void acl_cache_deinit(struct acl_cache **cache);
 
 struct acl_mask *acl_cache_mask_init(struct acl_cache *cache, pool_t pool,
@@ -31,9 +32,15 @@
 /* Flush cache for all objects */
 void acl_cache_flush_all(struct acl_cache *cache);
 
-/* Update object ACLs */
+/* Update object ACLs. */
 void acl_cache_update(struct acl_cache *cache, const char *objname,
 		      const struct acl_rights *rights);
+/* Update ACL object validity. */
+void acl_cache_set_validity(struct acl_cache *cache, const char *objname,
+			    const void *validity);
+/* Return ACL object validity. */
+const void *acl_cache_get_validity(struct acl_cache *cache,
+				   const char *objname);
 
 /* Returns all the right names currently created. The returned pointer may
    change after calling acl_cache_update(). */

Index: acl-storage.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/plugins/acl/acl-storage.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- acl-storage.c	27 Feb 2006 16:30:39 -0000	1.1
+++ acl-storage.c	28 Feb 2006 12:38:20 -0000	1.2
@@ -65,6 +65,7 @@
 	struct acl_mail_storage *astorage = ACL_CONTEXT(storage);
 
 	acl_backend_deinit(&astorage->backend);
+	astorage->super.destroy(storage);
 }
 
 static struct mailbox *



More information about the dovecot-cvs mailing list