[Libguestfs] [nbdkit PATCH 1/3] server: Allow filters to reduce thread model dynamically

Eric Blake eblake at redhat.com
Fri May 17 20:20:44 UTC 2019


Delay the initialization of the thread model until after
backend->config_complete; this is safe, since we don't make any lock
calls until backend->connect. Then add a function callback that
filters can use to further reduce things based on runtime
configuration.

Signed-off-by: Eric Blake <eblake at redhat.com>

---

Is it worth having filters both #define THREAD_MODEL and optionally
declare .thread_model? We have no API stability requirements; we could
instead declare that NBDKIT_REGISTER_FILTER() does NOT require a macro
THREAD_MODEL, and that .thread_model is optional (defaulting to
parallel, but MUST be provided by filters that want to reduce things).
---
 docs/nbdkit-filter.pod  | 25 ++++++++++++++++++++++---
 include/nbdkit-filter.h |  1 +
 server/filters.c        |  8 ++++++++
 server/main.c           | 10 ++++++----
 4 files changed, 37 insertions(+), 7 deletions(-)

diff --git a/docs/nbdkit-filter.pod b/docs/nbdkit-filter.pod
index 857f241..4033789 100644
--- a/docs/nbdkit-filter.pod
+++ b/docs/nbdkit-filter.pod
@@ -109,12 +109,16 @@ All filters should start by including this header file.

 =head1 C<#define THREAD_MODEL>

-All filters must define a thread model.  See
-L<nbdkit-plugin(3)/THREADS> for a discussion of thread models.
+All filters must define a default thread model by defining
+C<THREAD_MODEL>.  See L<nbdkit-plugin(3)/THREADS> for a discussion of
+thread models.

 The final thread model is the smallest (ie. most serialized) out of
 all the filters and the plugin.  Filters cannot alter the thread model
-to make it larger (more parallel).
+to make it larger (more parallel).  However, they can dynamically
+request a smaller (more serialized) model from decisions made during
+C<.config> and C<.config_complete>, by implementing a <.thread_model>
+function callback.

 If possible filters should be be written to handle fully parallel
 requests (C<NBDKIT_THREAD_MODEL_PARALLEL>, even multiple requests
@@ -267,6 +271,21 @@ what already appears in C<.description>.
 If the filter doesn't take any config parameters you should probably
 omit this.

+=head2 C<.thread_model>
+
+ int (*thread_model) (void);
+
+This optional function is called after C<.config_complete> to provide
+the filter an opportunity to reduce the resulting thread model below
+the value used at compilation via C<THREAD_MODEL>. The resulting
+thread model for all connections is determined by selecting the most
+restrictive model from the C<THREAD_MODEL> of the plugin and all
+filters, and from the results of any C<.thread_model> across all
+filters.
+
+If there is an error, C<.thread_model> should call C<nbdkit_error>
+with an error message and return C<-1>.
+
 =head2 C<.open>

  void * (*open) (nbdkit_next_open *next, void *nxdata,
diff --git a/include/nbdkit-filter.h b/include/nbdkit-filter.h
index 5893dd8..70d32ce 100644
--- a/include/nbdkit-filter.h
+++ b/include/nbdkit-filter.h
@@ -115,6 +115,7 @@ struct nbdkit_filter {
                  const char *key, const char *value);
   int (*config_complete) (nbdkit_next_config_complete *next, void *nxdata);
   const char *config_help;
+  int (*thread_model) (void);

   void * (*open) (nbdkit_next_open *next, void *nxdata,
                   int readonly);
diff --git a/server/filters.c b/server/filters.c
index 3bd91fe..87a9c0e 100644
--- a/server/filters.c
+++ b/server/filters.c
@@ -99,6 +99,14 @@ filter_thread_model (struct backend *b)
   if (filter_thread_model < thread_model) /* more serialized */
     thread_model = filter_thread_model;

+  if (f->filter.thread_model) {
+    filter_thread_model = f->filter.thread_model ();
+    if (filter_thread_model == -1)
+      exit (EXIT_FAILURE);
+    if (filter_thread_model < thread_model)
+      thread_model = filter_thread_model;
+  }
+
   return thread_model;
 }

diff --git a/server/main.c b/server/main.c
index 8ad3f7a..d46888a 100644
--- a/server/main.c
+++ b/server/main.c
@@ -1,5 +1,5 @@
 /* nbdkit
- * Copyright (C) 2013-2018 Red Hat Inc.
+ * Copyright (C) 2013-2019 Red Hat Inc.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -568,9 +568,6 @@ main (int argc, char *argv[])
     debug_flags = next;
   }

-  /* Select a thread model. */
-  lock_init_thread_model ();
-
   if (help) {
     struct backend *b;

@@ -643,6 +640,11 @@ main (int argc, char *argv[])

   backend->config_complete (backend);

+  /* Select a thread model. Plugin models are fixed at compile time,
+   * but filters are allowed to reduce the level during config.
+   */
+  lock_init_thread_model ();
+
   start_serving ();

   backend->free (backend);
-- 
2.20.1




More information about the Libguestfs mailing list