[RFC] Split notmuch_database_close into two functions

classic Classic list List threaded Threaded
43 messages Options
123
Justus Winter Justus Winter
Reply | Threaded
Open this post in threaded view
|

[RFC] Split notmuch_database_close into two functions

I propose to split the function notmuch_database_close into
notmuch_database_close and notmuch_database_destroy so that long
running processes like alot can close the database while still using
data obtained from queries to that database.

I've updated the tools, the go, ruby and python bindings to use
notmuch_database_destroy instead of notmuch_database_close to destroy
database objects.

Cheers,
Justus
_______________________________________________
notmuch mailing list
[hidden email]
http://notmuchmail.org/mailman/listinfo/notmuch
Justus Winter Justus Winter
Reply | Threaded
Open this post in threaded view
|

[PATCH 1/7] Split notmuch_database_close into two functions

Formerly notmuch_database_close closed the xapian database and
destroyed the talloc structure associated with the notmuch database
object. Split notmuch_database_close into notmuch_database_close and
notmuch_database_destroy.

This makes it possible for long running programs to close the xapian
database and thus release the lock associated with it without
destroying the data structures obtained from it.

This also makes the api more consistent since every other data
structure has a destructor function.

Signed-off-by: Justus Winter <[hidden email]>
---
 lib/database.cc |   14 ++++++++++++--
 lib/notmuch.h   |   15 +++++++++++----
 2 files changed, 23 insertions(+), 6 deletions(-)

diff --git a/lib/database.cc b/lib/database.cc
index 16c4354..2fefcad 100644
--- a/lib/database.cc
+++ b/lib/database.cc
@@ -642,7 +642,7 @@ notmuch_database_open (const char *path,
  "       read-write mode.\n",
  notmuch_path, version, NOTMUCH_DATABASE_VERSION);
  notmuch->mode = NOTMUCH_DATABASE_MODE_READ_ONLY;
- notmuch_database_close (notmuch);
+ notmuch_database_destroy (notmuch);
  notmuch = NULL;
  goto DONE;
     }
@@ -702,7 +702,7 @@ notmuch_database_open (const char *path,
     } catch (const Xapian::Error &error) {
  fprintf (stderr, "A Xapian exception occurred opening database: %s\n",
  error.get_msg().c_str());
- notmuch_database_close (notmuch);
+ notmuch_database_destroy (notmuch);
  notmuch = NULL;
     }
 
@@ -738,9 +738,19 @@ notmuch_database_close (notmuch_database_t *notmuch)
     }
 
     delete notmuch->term_gen;
+    notmuch->term_gen = NULL;
     delete notmuch->query_parser;
+    notmuch->query_parser = NULL;
     delete notmuch->xapian_db;
+    notmuch->xapian_db = NULL;
     delete notmuch->value_range_processor;
+    notmuch->value_range_processor = NULL;
+}
+
+void
+notmuch_database_destroy (notmuch_database_t *notmuch)
+{
+    notmuch_database_close (notmuch);
     talloc_free (notmuch);
 }
 
diff --git a/lib/notmuch.h b/lib/notmuch.h
index babd208..6114f36 100644
--- a/lib/notmuch.h
+++ b/lib/notmuch.h
@@ -133,7 +133,7 @@ typedef struct _notmuch_filenames notmuch_filenames_t;
  *
  * After a successful call to notmuch_database_create, the returned
  * database will be open so the caller should call
- * notmuch_database_close when finished with it.
+ * notmuch_database_destroy when finished with it.
  *
  * The database will not yet have any data in it
  * (notmuch_database_create itself is a very cheap function). Messages
@@ -165,7 +165,7 @@ typedef enum {
  * An existing notmuch database can be identified by the presence of a
  * directory named ".notmuch" below 'path'.
  *
- * The caller should call notmuch_database_close when finished with
+ * The caller should call notmuch_database_destroy when finished with
  * this database.
  *
  * In case of any failure, this function returns NULL, (after printing
@@ -175,11 +175,18 @@ notmuch_database_t *
 notmuch_database_open (const char *path,
        notmuch_database_mode_t mode);
 
-/* Close the given notmuch database, freeing all associated
- * resources. See notmuch_database_open. */
+/* Close the given notmuch database.
+ *
+ * This function is called by notmuch_database_destroyed and can be
+ * called multiple times. */
 void
 notmuch_database_close (notmuch_database_t *database);
 
+/* Destroy the notmuch database freeing all associated
+ * resources */
+void
+notmuch_database_destroy (notmuch_database_t *database);
+
 /* Return the database path of the given database.
  *
  * The return value is a string owned by notmuch so should not be
--
1.7.9.1

_______________________________________________
notmuch mailing list
[hidden email]
http://notmuchmail.org/mailman/listinfo/notmuch
Justus Winter Justus Winter
Reply | Threaded
Open this post in threaded view
|

[PATCH 2/7] NEWS: Document the notmuch_database_close split

In reply to this post by Justus Winter
Signed-off-by: Justus Winter <[hidden email]>
---
 NEWS |   12 ++++++++++++
 1 files changed, 12 insertions(+), 0 deletions(-)

diff --git a/NEWS b/NEWS
index ed5e3c5..26fce67 100644
--- a/NEWS
+++ b/NEWS
@@ -52,6 +52,18 @@ Reply improvement using the JSON format
   reply body, and it will quote HTML parts if no text/plain parts are
   available.
 
+Library changes
+---------------
+
+API changes
+
+  The function notmuch_database_close has been split into
+  notmuch_database_close and notmuch_database_destroy.
+
+  This makes it possible for long running programs to close the xapian
+  database and thus release the lock associated with it without
+  destroying the data structures obtained from it.
+
 Notmuch 0.12 (2012-03-20)
 =========================
 
--
1.7.9.1

_______________________________________________
notmuch mailing list
[hidden email]
http://notmuchmail.org/mailman/listinfo/notmuch
Justus Winter Justus Winter
Reply | Threaded
Open this post in threaded view
|

[PATCH 3/7] Use notmuch_database_destroy instead of notmuch_database_close

In reply to this post by Justus Winter
Adapt the notmuch binaries source to the notmuch_database_close split.

Signed-off-by: Justus Winter <[hidden email]>
---
 notmuch-count.c   |    2 +-
 notmuch-dump.c    |    2 +-
 notmuch-new.c     |    2 +-
 notmuch-reply.c   |    2 +-
 notmuch-restore.c |    2 +-
 notmuch-search.c  |    2 +-
 notmuch-show.c    |    2 +-
 notmuch-tag.c     |    2 +-
 8 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/notmuch-count.c b/notmuch-count.c
index 46b76ae..ade9138 100644
--- a/notmuch-count.c
+++ b/notmuch-count.c
@@ -100,7 +100,7 @@ notmuch_count_command (void *ctx, int argc, char *argv[])
     }
 
     notmuch_query_destroy (query);
-    notmuch_database_close (notmuch);
+    notmuch_database_destroy (notmuch);
 
     return 0;
 }
diff --git a/notmuch-dump.c b/notmuch-dump.c
index a735875..71ab0ea 100644
--- a/notmuch-dump.c
+++ b/notmuch-dump.c
@@ -116,7 +116,7 @@ notmuch_dump_command (unused (void *ctx), int argc, char *argv[])
  fclose (output);
 
     notmuch_query_destroy (query);
-    notmuch_database_close (notmuch);
+    notmuch_database_destroy (notmuch);
 
     return 0;
 }
diff --git a/notmuch-new.c b/notmuch-new.c
index 4f13535..f078753 100644
--- a/notmuch-new.c
+++ b/notmuch-new.c
@@ -1017,7 +1017,7 @@ notmuch_new_command (void *ctx, int argc, char *argv[])
  notmuch_status_to_string (ret));
     }
 
-    notmuch_database_close (notmuch);
+    notmuch_database_destroy (notmuch);
 
     if (run_hooks && !ret && !interrupted)
  ret = notmuch_run_hook (db_path, "post-new");
diff --git a/notmuch-reply.c b/notmuch-reply.c
index e2b6c25..1684b20 100644
--- a/notmuch-reply.c
+++ b/notmuch-reply.c
@@ -804,7 +804,7 @@ notmuch_reply_command (void *ctx, int argc, char *argv[])
  return 1;
 
     notmuch_query_destroy (query);
-    notmuch_database_close (notmuch);
+    notmuch_database_destroy (notmuch);
 
     if (params.cryptoctx)
  g_object_unref(params.cryptoctx);
diff --git a/notmuch-restore.c b/notmuch-restore.c
index 87d9772..60efc52 100644
--- a/notmuch-restore.c
+++ b/notmuch-restore.c
@@ -184,7 +184,7 @@ notmuch_restore_command (unused (void *ctx), int argc, char *argv[])
     if (line)
  free (line);
 
-    notmuch_database_close (notmuch);
+    notmuch_database_destroy (notmuch);
     if (input != stdin)
  fclose (input);
 
diff --git a/notmuch-search.c b/notmuch-search.c
index f6061e4..0b41573 100644
--- a/notmuch-search.c
+++ b/notmuch-search.c
@@ -531,7 +531,7 @@ notmuch_search_command (void *ctx, int argc, char *argv[])
     }
 
     notmuch_query_destroy (query);
-    notmuch_database_close (notmuch);
+    notmuch_database_destroy (notmuch);
 
     return ret;
 }
diff --git a/notmuch-show.c b/notmuch-show.c
index ff9d427..c2eaa44 100644
--- a/notmuch-show.c
+++ b/notmuch-show.c
@@ -1119,7 +1119,7 @@ notmuch_show_command (void *ctx, unused (int argc), unused (char *argv[]))
 
 
     notmuch_query_destroy (query);
-    notmuch_database_close (notmuch);
+    notmuch_database_destroy (notmuch);
 
     if (params.cryptoctx)
  g_object_unref(params.cryptoctx);
diff --git a/notmuch-tag.c b/notmuch-tag.c
index 36b9b09..142005c 100644
--- a/notmuch-tag.c
+++ b/notmuch-tag.c
@@ -227,7 +227,7 @@ notmuch_tag_command (void *ctx, int argc, char *argv[])
     }
 
     notmuch_query_destroy (query);
-    notmuch_database_close (notmuch);
+    notmuch_database_destroy (notmuch);
 
     return interrupted;
 }
--
1.7.9.1

_______________________________________________
notmuch mailing list
[hidden email]
http://notmuchmail.org/mailman/listinfo/notmuch
Justus Winter Justus Winter
Reply | Threaded
Open this post in threaded view
|

[PATCH 4/7] Use notmuch_database_destroy instead of notmuch_database_close

In reply to this post by Justus Winter
Adapt notmuch-deliver to the notmuch_database_close split.

Signed-off-by: Justus Winter <[hidden email]>
---
 contrib/notmuch-deliver/src/main.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/contrib/notmuch-deliver/src/main.c b/contrib/notmuch-deliver/src/main.c
index 6f32f73..37d2919 100644
--- a/contrib/notmuch-deliver/src/main.c
+++ b/contrib/notmuch-deliver/src/main.c
@@ -455,7 +455,7 @@ main(int argc, char **argv)
  g_strfreev(opt_rtags);
  g_free(mail);
 
- notmuch_database_close(db);
+ notmuch_database_destroy(db);
 
  return 0;
 }
--
1.7.9.1

_______________________________________________
notmuch mailing list
[hidden email]
http://notmuchmail.org/mailman/listinfo/notmuch
Justus Winter Justus Winter
Reply | Threaded
Open this post in threaded view
|

[PATCH 5/7] go: Use notmuch_database_destroy instead of notmuch_database_close

In reply to this post by Justus Winter
Adapt the go bindings to the notmuch_database_close split.

Signed-off-by: Justus Winter <[hidden email]>
---
 bindings/go/pkg/notmuch.go |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/bindings/go/pkg/notmuch.go b/bindings/go/pkg/notmuch.go
index c6844ef..d32901d 100644
--- a/bindings/go/pkg/notmuch.go
+++ b/bindings/go/pkg/notmuch.go
@@ -114,7 +114,7 @@ func NewDatabase(path string) *Database {
  * An existing notmuch database can be identified by the presence of a
  * directory named ".notmuch" below 'path'.
  *
- * The caller should call notmuch_database_close when finished with
+ * The caller should call notmuch_database_destroy when finished with
  * this database.
  *
  * In case of any failure, this function returns NULL, (after printing
@@ -140,7 +140,7 @@ func OpenDatabase(path string, mode DatabaseMode) *Database {
 /* Close the given notmuch database, freeing all associated
  * resources. See notmuch_database_open. */
 func (self *Database) Close() {
- C.notmuch_database_close(self.db)
+ C.notmuch_database_destroy(self.db)
 }
 
 /* Return the database path of the given database.
--
1.7.9.1

_______________________________________________
notmuch mailing list
[hidden email]
http://notmuchmail.org/mailman/listinfo/notmuch
Justus Winter Justus Winter
Reply | Threaded
Open this post in threaded view
|

[PATCH 6/7] ruby: Use notmuch_database_destroy instead of notmuch_database_close

In reply to this post by Justus Winter
Adapt the ruby bindings to the notmuch_database_close split.

Signed-off-by: Justus Winter <[hidden email]>
---
 bindings/ruby/database.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/bindings/ruby/database.c b/bindings/ruby/database.c
index 982fd59..ba9a139 100644
--- a/bindings/ruby/database.c
+++ b/bindings/ruby/database.c
@@ -110,7 +110,7 @@ notmuch_rb_database_close (VALUE self)
     notmuch_database_t *db;
 
     Data_Get_Notmuch_Database (self, db);
-    notmuch_database_close (db);
+    notmuch_database_destroy (db);
     DATA_PTR (self) = NULL;
 
     return Qnil;
--
1.7.9.1

_______________________________________________
notmuch mailing list
[hidden email]
http://notmuchmail.org/mailman/listinfo/notmuch
Justus Winter Justus Winter
Reply | Threaded
Open this post in threaded view
|

[PATCH 7/7] python: wrap and use notmuch_database_destroy as destructor

In reply to this post by Justus Winter
Adapt the go bindings to the notmuch_database_close split.

Signed-off-by: Justus Winter <[hidden email]>
---
 bindings/python/notmuch/database.py |   17 +++++++++++++++--
 1 files changed, 15 insertions(+), 2 deletions(-)

diff --git a/bindings/python/notmuch/database.py b/bindings/python/notmuch/database.py
index 44d40fd..9a1896b 100644
--- a/bindings/python/notmuch/database.py
+++ b/bindings/python/notmuch/database.py
@@ -218,9 +218,22 @@ class Database(object):
     _close.restype = None
 
     def close(self):
-        """Close and free the notmuch database if needed"""
-        if self._db is not None:
+        '''
+        Closes the notmuch database.
+        '''
+        if self._db:
             self._close(self._db)
+
+    _destroy = nmlib.notmuch_database_destroy
+    _destroy.argtypes = [NotmuchDatabaseP]
+    _destroy.restype = None
+
+    def destroy(self):
+        '''
+        Destroys the notmuch database.
+        '''
+        if self._db:
+            self._destroy(self._db)
             self._db = None
 
     def __enter__(self):
--
1.7.9.1

_______________________________________________
notmuch mailing list
[hidden email]
http://notmuchmail.org/mailman/listinfo/notmuch
Patrick Totzke Patrick Totzke
Reply | Threaded
Open this post in threaded view
|

Re: [RFC] Split notmuch_database_close into two functions

In reply to this post by Justus Winter
Hi all,

I can confirm that this fixes a rather nasty core dump in a branch of alot
that closes and re-opens the database more frequently.
/p
_______________________________________________
notmuch mailing list
[hidden email]
http://notmuchmail.org/mailman/listinfo/notmuch
Tomi Ollila-2 Tomi Ollila-2
Reply | Threaded
Open this post in threaded view
|

Re: [RFC] Split notmuch_database_close into two functions

In reply to this post by Justus Winter
Justus Winter <[hidden email]> writes:

> I propose to split the function notmuch_database_close into
> notmuch_database_close and notmuch_database_destroy so that long
> running processes like alot can close the database while still using
> data obtained from queries to that database.
>
> I've updated the tools, the go, ruby and python bindings to use
> notmuch_database_destroy instead of notmuch_database_close to destroy
> database objects.

This looks like a good idea. grep _destroy *.c outputs plenty of
other matches so this is not a new term here. I wonder what (backward)
compability issues there are, though.

In message id:"[hidden email]"
there was typo in comment: notmuch_database_destroyed ?

>
> Cheers,
> Justus

Tomi
_______________________________________________
notmuch mailing list
[hidden email]
http://notmuchmail.org/mailman/listinfo/notmuch
Justus Winter Justus Winter
Reply | Threaded
Open this post in threaded view
|

Re: [RFC] Split notmuch_database_close into two functions

You're right of course, updated patch sent as a follow up.

Justus
_______________________________________________
notmuch mailing list
[hidden email]
http://notmuchmail.org/mailman/listinfo/notmuch
Justus Winter Justus Winter
Reply | Threaded
Open this post in threaded view
|

[PATCH 1/7] Split notmuch_database_close into two functions

Formerly notmuch_database_close closed the xapian database and
destroyed the talloc structure associated with the notmuch database
object. Split notmuch_database_close into notmuch_database_close and
notmuch_database_destroy.

This makes it possible for long running programs to close the xapian
database and thus release the lock associated with it without
destroying the data structures obtained from it.

This also makes the api more consistent since every other data
structure has a destructor function.

Signed-off-by: Justus Winter <[hidden email]>
---
 lib/database.cc |   14 ++++++++++++--
 lib/notmuch.h   |   15 +++++++++++----
 2 files changed, 23 insertions(+), 6 deletions(-)

diff --git a/lib/database.cc b/lib/database.cc
index 16c4354..2fefcad 100644
--- a/lib/database.cc
+++ b/lib/database.cc
@@ -642,7 +642,7 @@ notmuch_database_open (const char *path,
  "       read-write mode.\n",
  notmuch_path, version, NOTMUCH_DATABASE_VERSION);
  notmuch->mode = NOTMUCH_DATABASE_MODE_READ_ONLY;
- notmuch_database_close (notmuch);
+ notmuch_database_destroy (notmuch);
  notmuch = NULL;
  goto DONE;
     }
@@ -702,7 +702,7 @@ notmuch_database_open (const char *path,
     } catch (const Xapian::Error &error) {
  fprintf (stderr, "A Xapian exception occurred opening database: %s\n",
  error.get_msg().c_str());
- notmuch_database_close (notmuch);
+ notmuch_database_destroy (notmuch);
  notmuch = NULL;
     }
 
@@ -738,9 +738,19 @@ notmuch_database_close (notmuch_database_t *notmuch)
     }
 
     delete notmuch->term_gen;
+    notmuch->term_gen = NULL;
     delete notmuch->query_parser;
+    notmuch->query_parser = NULL;
     delete notmuch->xapian_db;
+    notmuch->xapian_db = NULL;
     delete notmuch->value_range_processor;
+    notmuch->value_range_processor = NULL;
+}
+
+void
+notmuch_database_destroy (notmuch_database_t *notmuch)
+{
+    notmuch_database_close (notmuch);
     talloc_free (notmuch);
 }
 
diff --git a/lib/notmuch.h b/lib/notmuch.h
index babd208..2fb4e70 100644
--- a/lib/notmuch.h
+++ b/lib/notmuch.h
@@ -133,7 +133,7 @@ typedef struct _notmuch_filenames notmuch_filenames_t;
  *
  * After a successful call to notmuch_database_create, the returned
  * database will be open so the caller should call
- * notmuch_database_close when finished with it.
+ * notmuch_database_destroy when finished with it.
  *
  * The database will not yet have any data in it
  * (notmuch_database_create itself is a very cheap function). Messages
@@ -165,7 +165,7 @@ typedef enum {
  * An existing notmuch database can be identified by the presence of a
  * directory named ".notmuch" below 'path'.
  *
- * The caller should call notmuch_database_close when finished with
+ * The caller should call notmuch_database_destroy when finished with
  * this database.
  *
  * In case of any failure, this function returns NULL, (after printing
@@ -175,11 +175,18 @@ notmuch_database_t *
 notmuch_database_open (const char *path,
        notmuch_database_mode_t mode);
 
-/* Close the given notmuch database, freeing all associated
- * resources. See notmuch_database_open. */
+/* Close the given notmuch database.
+ *
+ * This function is called by notmuch_database_destroy and can be
+ * called multiple times. */
 void
 notmuch_database_close (notmuch_database_t *database);
 
+/* Destroy the notmuch database freeing all associated
+ * resources */
+void
+notmuch_database_destroy (notmuch_database_t *database);
+
 /* Return the database path of the given database.
  *
  * The return value is a string owned by notmuch so should not be
--
1.7.9.1

_______________________________________________
notmuch mailing list
[hidden email]
http://notmuchmail.org/mailman/listinfo/notmuch
Mark Walters Mark Walters
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH 1/7] Split notmuch_database_close into two functions

In reply to this post by Justus Winter
Justus Winter <[hidden email]> writes:

> Formerly notmuch_database_close closed the xapian database and
> destroyed the talloc structure associated with the notmuch database
> object. Split notmuch_database_close into notmuch_database_close and
> notmuch_database_destroy.
>
> This makes it possible for long running programs to close the xapian
> database and thus release the lock associated with it without
> destroying the data structures obtained from it.
>
> This also makes the api more consistent since every other data
> structure has a destructor function.

I like the idea of this series but have two queries before reviewing it.

The first is a concern that if we change the library functions we should
update the library version otherwise out of tree users won't know which
to call. (I don't actually know how versioning is done but I think we
should at least be able to make new out-of-tree code cope with the old
or new version). It might be worth keeping notmuch_database_close as it
is for now and adding something like notmuch_database_weak_close with
the new functionality. Then whenever the library version is next going
to get bumped we could move to the destroy/close nomenclature.

Secondly, I think the patch series could be made clearer and easier to
review. If you do it in three steps

1) change of notmuch_database_close to notmuch_database_destroy (just
   the function name change)
2) split the new notmuch_database_destroy into two as in the current
   first patch
3) Make any changes (if there are any) of notmuch_database_destroy to
   notmuch_database_close.

The advantage is that the first change is easy to test (essentially does
it build) and then changes from notmuch_database_destroy to
notmuch_database_close in step 3 are explicit rather than the current
situation where we need to grep the code to see if some instances of
notmuch_database_close were not changed to notmuch_database_destroy.

Of course if the decision is to go via the weak_close version then you
just need to do the analogues of 2 and 3.

Best wishes

Mark

>
> Signed-off-by: Justus Winter <[hidden email]>
> ---
>  lib/database.cc |   14 ++++++++++++--
>  lib/notmuch.h   |   15 +++++++++++----
>  2 files changed, 23 insertions(+), 6 deletions(-)
>
> diff --git a/lib/database.cc b/lib/database.cc
> index 16c4354..2fefcad 100644
> --- a/lib/database.cc
> +++ b/lib/database.cc
> @@ -642,7 +642,7 @@ notmuch_database_open (const char *path,
>   "       read-write mode.\n",
>   notmuch_path, version, NOTMUCH_DATABASE_VERSION);
>   notmuch->mode = NOTMUCH_DATABASE_MODE_READ_ONLY;
> - notmuch_database_close (notmuch);
> + notmuch_database_destroy (notmuch);
>   notmuch = NULL;
>   goto DONE;
>      }
> @@ -702,7 +702,7 @@ notmuch_database_open (const char *path,
>      } catch (const Xapian::Error &error) {
>   fprintf (stderr, "A Xapian exception occurred opening database: %s\n",
>   error.get_msg().c_str());
> - notmuch_database_close (notmuch);
> + notmuch_database_destroy (notmuch);
>   notmuch = NULL;
>      }
>  
> @@ -738,9 +738,19 @@ notmuch_database_close (notmuch_database_t *notmuch)
>      }
>  
>      delete notmuch->term_gen;
> +    notmuch->term_gen = NULL;
>      delete notmuch->query_parser;
> +    notmuch->query_parser = NULL;
>      delete notmuch->xapian_db;
> +    notmuch->xapian_db = NULL;
>      delete notmuch->value_range_processor;
> +    notmuch->value_range_processor = NULL;
> +}
> +
> +void
> +notmuch_database_destroy (notmuch_database_t *notmuch)
> +{
> +    notmuch_database_close (notmuch);
>      talloc_free (notmuch);
>  }
>  
> diff --git a/lib/notmuch.h b/lib/notmuch.h
> index babd208..6114f36 100644
> --- a/lib/notmuch.h
> +++ b/lib/notmuch.h
> @@ -133,7 +133,7 @@ typedef struct _notmuch_filenames notmuch_filenames_t;
>   *
>   * After a successful call to notmuch_database_create, the returned
>   * database will be open so the caller should call
> - * notmuch_database_close when finished with it.
> + * notmuch_database_destroy when finished with it.
>   *
>   * The database will not yet have any data in it
>   * (notmuch_database_create itself is a very cheap function). Messages
> @@ -165,7 +165,7 @@ typedef enum {
>   * An existing notmuch database can be identified by the presence of a
>   * directory named ".notmuch" below 'path'.
>   *
> - * The caller should call notmuch_database_close when finished with
> + * The caller should call notmuch_database_destroy when finished with
>   * this database.
>   *
>   * In case of any failure, this function returns NULL, (after printing
> @@ -175,11 +175,18 @@ notmuch_database_t *
>  notmuch_database_open (const char *path,
>         notmuch_database_mode_t mode);
>  
> -/* Close the given notmuch database, freeing all associated
> - * resources. See notmuch_database_open. */
> +/* Close the given notmuch database.
> + *
> + * This function is called by notmuch_database_destroyed and can be
> + * called multiple times. */
>  void
>  notmuch_database_close (notmuch_database_t *database);
>  
> +/* Destroy the notmuch database freeing all associated
> + * resources */
> +void
> +notmuch_database_destroy (notmuch_database_t *database);
> +
>  /* Return the database path of the given database.
>   *
>   * The return value is a string owned by notmuch so should not be
> --
> 1.7.9.1
>
> _______________________________________________
> notmuch mailing list
> [hidden email]
> http://notmuchmail.org/mailman/listinfo/notmuch
_______________________________________________
notmuch mailing list
[hidden email]
http://notmuchmail.org/mailman/listinfo/notmuch
David Bremner-4 David Bremner-4
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH 1/7] Split notmuch_database_close into two functions

Mark Walters <[hidden email]> writes:

> The first is a concern that if we change the library functions we should
> update the library version otherwise out of tree users won't know which
> to call.

This is not such a big deal. We can update the SONAME of the library so
that old code will continute to dynamically link to the old version of
the library. Nothing [1] will magically make the old code work with the
new library if we change the API; that is just the way things go,
occasionally APIs and/or ABIs change.

[1] Well maybe symbol versioning. I don't fully understand that, but I
suspect it is more trouble than it is worth.
_______________________________________________
notmuch mailing list
[hidden email]
http://notmuchmail.org/mailman/listinfo/notmuch
Austin Clements Austin Clements
Reply | Threaded
Open this post in threaded view
|

Re: [RFC] Split notmuch_database_close into two functions

In reply to this post by Justus Winter
Quoth Justus Winter on Mar 21 at  1:55 am:
> I propose to split the function notmuch_database_close into
> notmuch_database_close and notmuch_database_destroy so that long
> running processes like alot can close the database while still using
> data obtained from queries to that database.

Is this actually safe?  My understanding of Xapian::Database::close is
that, once you've closed the database, basically anything can throw a
Xapian exception.  A lot of data is retrieved lazily, both by notmuch
and by Xapian, so simply having, say, a notmuch_message_t object isn't
enough to guarantee that you'll be able to get data out of it after
closing the database.  Hence, I don't see how this interface could be
used correctly.

Maybe you could describe your use case in more detail?
_______________________________________________
notmuch mailing list
[hidden email]
http://notmuchmail.org/mailman/listinfo/notmuch
Justus Winter Justus Winter
Reply | Threaded
Open this post in threaded view
|

Re: [RFC] Split notmuch_database_close into two functions

Quoting Austin Clements (2012-04-01 05:23:23)

>Quoth Justus Winter on Mar 21 at  1:55 am:
>> I propose to split the function notmuch_database_close into
>> notmuch_database_close and notmuch_database_destroy so that long
>> running processes like alot can close the database while still using
>> data obtained from queries to that database.
>
>Is this actually safe?  My understanding of Xapian::Database::close is
>that, once you've closed the database, basically anything can throw a
>Xapian exception.  A lot of data is retrieved lazily, both by notmuch
>and by Xapian, so simply having, say, a notmuch_message_t object isn't
>enough to guarantee that you'll be able to get data out of it after
>closing the database.  Hence, I don't see how this interface could be
>used correctly.

I do not know how, but both alot and afew (and occasionally the
notmuch binary) are somehow safely using this interface on my box for
the last three weeks.

>Maybe you could describe your use case in more detail?

Uh, okay. There are two long running processes (alot and afew in my
case) competing for a resource ("writable access to the notmuch
database"). This access is serialized by a lock maintained by
libxapian. This is a rather classic cs problem.

In order to avoid starvation of one process, both processes must
release the lock after a finite amount of time. Now for all practical
purposes the requirement is usually that both processes should
minimize the time spent while they aquired the lock.

The only way to ensure that the lock is released is to ask notmuch to
release the lock. When Patrick asked me for a way to release the lock
I exposed the function notmuch_database_close [0].

I made a mistake. The mistake was to assume that a function named
notmuch_database_close would actually do as the name implies. But that
wasn't the case. I should have been more suspicious, but being
somewhat naive I patched notmuch_database_close to actually close the
database [1].

I'm basically trying to correct that mistake. One way to fix that is
this patchset, the other one is to rename notmuch_database_close to
notmuch_database_destroy and to remove the ability to call this
function from the python bindings.

There is a branch of alot [2] that needs this functionality and hence
this patchset to avoid crashes (the ticket contains more information
why this leads to crashes). Incidentally this branch also fixes
another bug in alot [3]. Patrick spoke up in this thread stating that
this patchset is useful for alot. There is a unpublished branch of
afew that requires this functionality.

I think it very much boils down to the question whether or not
libnotmuch and its users are second class citizens. This issue is not
a problem for the notmuch binary since it is short lived in nature.

In fact I feel reminded of [4] when I pointed out problems in the code
that are problematic for libnotmuch users. You - Austin - suggested to
whip up patches instead of raising concerns. That's a valid response,
after all, talk is cheap ;)

But now that I have a patchset that is rather small (yes, it changes
the API but any program can be adjusted automatically using sed...)
and I kind of thought that it would be accepted more easily. And
although the changes are trivial it took me quite some time to track
it down.

The thread [4] dried out without someone like you or David stating
that he cares about libnotmuch and its users as much as the users of
the notmuch binary. These kind of problems require invasive code and
API changes, I asked in that very same thread how to do this properly
but noone answered.

I think I'm just not willing to devote my time to fix these problems
if these issues aren't even perceived as problems by the majority of
notmuch users and developers b/c they are using the emacs interface
which just calls the notmuch binary that has no such problems.

Cheers,
Justus

0: b2734519db78fdec76eeafc5fe8f5631a6436cf6
1: cfc5f1059aa16753cba610c41601cacc97260e08
2: https://github.com/pazz/alot/issues/413
3: https://github.com/pazz/alot/issues/414
4: [hidden email]
_______________________________________________
notmuch mailing list
[hidden email]
http://notmuchmail.org/mailman/listinfo/notmuch
Austin Clements Austin Clements
Reply | Threaded
Open this post in threaded view
|

Re: [RFC] Split notmuch_database_close into two functions

Quoth Justus Winter on Apr 12 at 11:05 am:

> Quoting Austin Clements (2012-04-01 05:23:23)
> >Quoth Justus Winter on Mar 21 at  1:55 am:
> >> I propose to split the function notmuch_database_close into
> >> notmuch_database_close and notmuch_database_destroy so that long
> >> running processes like alot can close the database while still using
> >> data obtained from queries to that database.
> >
> >Is this actually safe?  My understanding of Xapian::Database::close is
> >that, once you've closed the database, basically anything can throw a
> >Xapian exception.  A lot of data is retrieved lazily, both by notmuch
> >and by Xapian, so simply having, say, a notmuch_message_t object isn't
> >enough to guarantee that you'll be able to get data out of it after
> >closing the database.  Hence, I don't see how this interface could be
> >used correctly.
>
> I do not know how, but both alot and afew (and occasionally the
> notmuch binary) are somehow safely using this interface on my box for
> the last three weeks.

I see.  TL;DR: This isn't safe, but that's okay if we document it.

The bug report [0] you pointed to was quite informative.  At its core,
this is really a memory management issue.  To sum up for the record
(and to check my own thinking): It sounds like alot is careful not to
use any notmuch objects after closing the database.  The problem is
that, currently, closing the database also talloc_free's it, which
recursively free's everything derived from it.  Python later GCs the
wrapper objects, which *also* try to free their underlying objects,
resulting in a double free.

Before the change to expose notmuch_database_close, the Python
bindings would only talloc_free from destructors.  Furthermore, they
prevented the library from recursively freeing things at other times
by internally maintaining a reverse reference for every library talloc
reference (e.g., message is a sub-allocation of query, so the bindings
keep a reference from each message to its query to ensure the query
doesn't get freed).  The ability to explicitly talloc_free the
database subverts this mechanism.


So, I've come around to thinking that splitting notmuch_database_close
and _destroy is okay.  It certainly parallels the rest of the API
better.  However, notmuch_database_close needs a big warning similar
to Xapian::Database::close's warning that retrieving information from
objects derived from this database may not work after calling close.
notmuch_database_close is really a specialty interface, and about the
only thing you can guarantee after closing the database is that you
can destroy other objects.  This is also going to require a SONAME
major version bump, as mentioned by others.  Which, to be fair, would
be a good opportunity to fix some other issues, too, like how
notmuch_database_open can't return errors and how
notmuch_database_get_directory is broken on read-only databases.  The
actual bump should be done at release time, but maybe we should drop a
note somewhere (NEWS?) so we don't forget.

[0] https://github.com/pazz/alot/issues/413
_______________________________________________
notmuch mailing list
[hidden email]
http://notmuchmail.org/mailman/listinfo/notmuch
Austin Clements Austin Clements
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH 7/7] python: wrap and use notmuch_database_destroy as destructor

In reply to this post by Justus Winter
Quoth Justus Winter on Mar 21 at  1:55 am:
> Adapt the go bindings to the notmuch_database_close split.

Typo.

>
> Signed-off-by: Justus Winter <[hidden email]>
> ---
>  bindings/python/notmuch/database.py |   17 +++++++++++++++--
>  1 files changed, 15 insertions(+), 2 deletions(-)
>
> diff --git a/bindings/python/notmuch/database.py b/bindings/python/notmuch/database.py
> index 44d40fd..9a1896b 100644
> --- a/bindings/python/notmuch/database.py
> +++ b/bindings/python/notmuch/database.py
> @@ -218,9 +218,22 @@ class Database(object):
>      _close.restype = None
>  
>      def close(self):
> -        """Close and free the notmuch database if needed"""
> -        if self._db is not None:
> +        '''
> +        Closes the notmuch database.
> +        '''
> +        if self._db:
>              self._close(self._db)
> +
> +    _destroy = nmlib.notmuch_database_destroy
> +    _destroy.argtypes = [NotmuchDatabaseP]
> +    _destroy.restype = None
> +
> +    def destroy(self):

Should this be __del__?  The existing __del__ is certainly wrong with
this change, since it only closes the database and doesn't free it.  I
think this function is exactly what you want __del__ to be now.

(I think it also doesn't make sense to expose notmuch_database_destroy
as a general, public method since it will free all of the other C
objects out from under the bindings, resulting in exactly the double
free-type crashes that you're trying to avoid.  It appears that none
of the other Python classes have a destroy method.)

> +        '''
> +        Destroys the notmuch database.
> +        '''
> +        if self._db:
> +            self._destroy(self._db)
>              self._db = None
>  
>      def __enter__(self):
_______________________________________________
notmuch mailing list
[hidden email]
http://notmuchmail.org/mailman/listinfo/notmuch
Justus Winter Justus Winter
Reply | Threaded
Open this post in threaded view
|

Re: [RFC] Split notmuch_database_close into two functions

In reply to this post by Austin Clements
Quoting Austin Clements (2012-04-12 18:57:44)

>Quoth Justus Winter on Apr 12 at 11:05 am:
>> Quoting Austin Clements (2012-04-01 05:23:23)
>> >Quoth Justus Winter on Mar 21 at  1:55 am:
>> >> I propose to split the function notmuch_database_close into
>> >> notmuch_database_close and notmuch_database_destroy so that long
>> >> running processes like alot can close the database while still using
>> >> data obtained from queries to that database.
>> >
>> >Is this actually safe?  My understanding of Xapian::Database::close is
>> >that, once you've closed the database, basically anything can throw a
>> >Xapian exception.  A lot of data is retrieved lazily, both by notmuch
>> >and by Xapian, so simply having, say, a notmuch_message_t object isn't
>> >enough to guarantee that you'll be able to get data out of it after
>> >closing the database.  Hence, I don't see how this interface could be
>> >used correctly.
>>
>> I do not know how, but both alot and afew (and occasionally the
>> notmuch binary) are somehow safely using this interface on my box for
>> the last three weeks.
>
>I see.  TL;DR: This isn't safe, but that's okay if we document it.
>
>The bug report [0] you pointed to was quite informative.  At its core,
>this is really a memory management issue.  To sum up for the record
>(and to check my own thinking): It sounds like alot is careful not to
>use any notmuch objects after closing the database.  The problem is
>that, currently, closing the database also talloc_free's it, which
>recursively free's everything derived from it.  Python later GCs the
>wrapper objects, which *also* try to free their underlying objects,
>resulting in a double free.
>
>Before the change to expose notmuch_database_close, the Python
>bindings would only talloc_free from destructors.  Furthermore, they
>prevented the library from recursively freeing things at other times
>by internally maintaining a reverse reference for every library talloc
>reference (e.g., message is a sub-allocation of query, so the bindings
>keep a reference from each message to its query to ensure the query
>doesn't get freed).  The ability to explicitly talloc_free the
>database subverts this mechanism.

Exactly.

>So, I've come around to thinking that splitting notmuch_database_close
>and _destroy is okay.  It certainly parallels the rest of the API
>better.  However, notmuch_database_close needs a big warning similar
>to Xapian::Database::close's warning that retrieving information from
>objects derived from this database may not work after calling close.

Yes, but then again one should always expect function calls to fail
and most APIs have mechanisms to communicate failures.

OTOH this might be an indication that the notmuch API should be
redesigned. Both alot and afew have their own wrappers around the
notmuch API to work around some limitations (e.g. changes to messages
are enqueued and executed at some point, with some kind of mechanism
to cope with the notmuch database temporarily not being available,
message objects have to be re-fetched if they got outdated (IIRC,
whatever that means)).

Justus
_______________________________________________
notmuch mailing list
[hidden email]
http://notmuchmail.org/mailman/listinfo/notmuch
Justus Winter Justus Winter
Reply | Threaded
Open this post in threaded view
|

Re: [RFC] Split notmuch_database_close into two functions

In reply to this post by Austin Clements
Hi everyone,

Quoting Patrick Totzke (2012-04-13 10:33:58)

> Quoting Austin Clements (2012-04-01 04:23:23)
> >Maybe you could describe your use case in more detail?
>
> Quoting Austin Clements (2012-04-12 17:57:44)
> >Quoth Justus Winter on Apr 12 at 11:05 am:
> ...
> >I see.  TL;DR
>
> .. which should pretty much settle Austins opinion on
> libnotmuch users being second class citizens.

Na, I think you misinterpreted Austin here, I think he summarized his
position. Looking back at my mail I think I came across a lot harsher
than necessary, I'm sorry for that. Let's get back to the issue at
hand, shall we?

Both Austin and Mark seem to support the split, any other opinions?

Cheers,
Justus
_______________________________________________
notmuch mailing list
[hidden email]
http://notmuchmail.org/mailman/listinfo/notmuch
123