This timeout specifies the lifetime of a cache entry before it is
updated out-of-band. When this timeout is hit, the request will
still complete from cache, but the SSSD will also go and update
the cached entry in the background to extend the life of the
cache entry and reduce the wait time of a future request.

Support for the EnumCacheNoWaitRefreshTimeout is still forthcoming, but
I wanted to get a formal review on this portion.
-- 
Stephen Gallagher
RHCE 804006346421761

Looking to carve out IT costs?
www.redhat.com/carveoutcosts/
From c8d774ee2741c76c4c2a07bcae112924b0061e86 Mon Sep 17 00:00:00 2001
From: Stephen Gallagher <[email protected]>
Date: Fri, 14 Aug 2009 08:59:53 -0400
Subject: [PATCH] Add support for the EntryCacheNoWaitRefreshTimeout

This timeout specifies the lifetime of a cache entry before it is
updated out-of-band. When this timeout is hit, the request will
still complete from cache, but the SSSD will also go and update
the cached entry in the background to extend the life of the
cache entry and reduce the wait time of a future request.
---
 server/examples/sssd.conf         |   13 ++
 server/man/sssd.conf.5.xml        |   13 ++
 server/responder/nss/nsssrv.c     |   20 ++++
 server/responder/nss/nsssrv.h     |    7 +-
 server/responder/nss/nsssrv_cmd.c |  227 ++++++++++++++++++++++++++++++-------
 5 files changed, 236 insertions(+), 44 deletions(-)

diff --git a/server/examples/sssd.conf b/server/examples/sssd.conf
index d57bed7..197b1ab 100644
--- a/server/examples/sssd.conf
+++ b/server/examples/sssd.conf
@@ -13,6 +13,19 @@ description = NSS Responder Configuration
 filterGroups = root
 filterUsers = root
 
+# The EntryCacheTimeout indicates the number of seconds to retain before
+# an entry in cache is considered stale and must block to refresh.
+# The EntryCacheNoWaitRefreshTimeout indicates the number of seconds to
+# wait before updating the cache out-of-band. (NSS requests will still
+# be returned from cache until the full EntryCacheTimeout). Setting this
+# value to 0 turns this feature off (default)
+; EntryCacheTimeout = 600
+; EntryCacheNoWaitRefreshTimeout = 300
+
+# The EnumCacheTimeout indicates the number of seconds to retain before
+# an entry in cache is considered stale and must block to refresh.
+; EnumCacheTimeout = 120
+
 [services/dp]
 description = Data Provider Configuration
 
diff --git a/server/man/sssd.conf.5.xml b/server/man/sssd.conf.5.xml
index 6c5ce87..04925d2 100644
--- a/server/man/sssd.conf.5.xml
+++ b/server/man/sssd.conf.5.xml
@@ -324,6 +324,19 @@
                     </listitem>
                 </varlistentry>
                 <varlistentry>
+                    <term>EntryCacheNoWaitRefreshTimeout (integer)</term>
+                    <listitem>
+                        <para>
+                            How long should nss_sss return cached entries 
before
+                            initiating an out-of-band cache refresh (0 disables
+                            this feature)
+                        </para>
+                        <para>
+                            Default: 0
+                        </para>
+                    </listitem>
+                </varlistentry>
+                <varlistentry>
                     <term>EntryNegativeTimeout (integer)</term>
                     <listitem>
                         <para>
diff --git a/server/responder/nss/nsssrv.c b/server/responder/nss/nsssrv.c
index 456c629..6d7bf74 100644
--- a/server/responder/nss/nsssrv.c
+++ b/server/responder/nss/nsssrv.c
@@ -103,6 +103,26 @@ static int nss_get_config(struct nss_ctx *nctx,
                          &nctx->neg_timeout);
     if (ret != EOK) goto done;
 
+    ret = confdb_get_int(cdb, nctx, NSS_SRV_CONFIG,
+                         "EnumCacheNoWaitRefreshTimeout", 0,
+                         &nctx->enum_cache_refresh_timeout);
+    if (ret != EOK) goto done;
+    if (nctx->enum_cache_refresh_timeout >= nctx->enum_cache_timeout) {
+        DEBUG(0,("Configuration error: EnumCacheNoWaitRefreshTimeout exceeds"
+                 "EnumCacheTimeout. Disabling feature.\n"));
+        nctx->enum_cache_refresh_timeout = 0;
+    }
+
+    ret = confdb_get_int(cdb, nctx, NSS_SRV_CONFIG,
+                         "EntryCacheNoWaitRefreshTimeout", 0,
+                         &nctx->cache_refresh_timeout);
+    if (ret != EOK) goto done;
+    if (nctx->cache_refresh_timeout >= nctx->cache_timeout) {
+        DEBUG(0,("Configuration error: EntryCacheNoWaitRefreshTimeout exceeds"
+                 "EntryCacheTimeout. Disabling feature.\n"));
+        nctx->cache_refresh_timeout = 0;
+    }
+
     ret = confdb_get_string_as_list(cdb, tmpctx, NSS_SRV_CONFIG,
                                     "filterUsers", &filter_list);
     if (ret == ENOENT) filter_list = NULL;
diff --git a/server/responder/nss/nsssrv.h b/server/responder/nss/nsssrv.h
index 0d3124c..e756384 100644
--- a/server/responder/nss/nsssrv.h
+++ b/server/responder/nss/nsssrv.h
@@ -50,11 +50,14 @@ struct getent_ctx;
 struct nss_ctx {
     struct resp_ctx *rctx;
 
-    int cache_timeout;
-    int neg_timeout;
     struct nss_nc_ctx *ncache;
 
+    int neg_timeout;
+    int cache_timeout;
     int enum_cache_timeout;
+    int cache_refresh_timeout;
+    int enum_cache_refresh_timeout;
+
     time_t last_user_enum;
     time_t last_group_enum;
 
diff --git a/server/responder/nss/nsssrv_cmd.c 
b/server/responder/nss/nsssrv_cmd.c
index e8f178a..f00a423 100644
--- a/server/responder/nss/nsssrv_cmd.c
+++ b/server/responder/nss/nsssrv_cmd.c
@@ -273,12 +273,15 @@ static void nss_cmd_getpwnam_callback(void *ptr, int 
status,
     struct cli_ctx *cctx = cmdctx->cctx;
     struct sss_domain_info *dom;
     struct nss_ctx *nctx;
-    int timeout;
+    int timeout, refresh_timeout;
+    time_t now;
     uint64_t lastUpdate;
     uint8_t *body;
     size_t blen;
     bool call_provider = false;
     bool neghit = false;
+    bool need_callback = true;
+    sss_dp_callback_t cb = NULL;
     int ncret;
     int ret;
 
@@ -296,16 +299,33 @@ static void nss_cmd_getpwnam_callback(void *ptr, int 
status,
     if (dctx->check_provider) {
         switch (res->count) {
         case 0:
+            /* This is a cache miss. We need to get the updated user 
information
+             * before returning it.
+             */
             call_provider = true;
+            need_callback = true;
             break;
 
         case 1:
             timeout = nctx->cache_timeout;
-
+            refresh_timeout = nctx->cache_refresh_timeout;
             lastUpdate = ldb_msg_find_attr_as_uint64(res->msgs[0],
                                                      SYSDB_LAST_UPDATE, 0);
-            if (lastUpdate + timeout < time(NULL)) {
+            now = time(NULL);
+            if (lastUpdate + timeout < now) {
+                /* This is a cache miss. We need to get the updated user
+                 * information before returning it.
+                 */
+                call_provider = true;
+                need_callback = true;
+            }
+            else if (refresh_timeout && (lastUpdate + refresh_timeout < now)) {
+                /* We're past the the cache refresh timeout
+                 * We'll return the value from the cache, but we'll also
+                 * queue the cache entry for update out-of-band.
+                 */
                 call_provider = true;
+                need_callback = false;
             }
             break;
 
@@ -321,7 +341,6 @@ static void nss_cmd_getpwnam_callback(void *ptr, int status,
     }
 
     if (call_provider) {
-
         /* dont loop forever :-) */
         dctx->check_provider = false;
         timeout = SSS_CLI_SOCKET_TIMEOUT/2;
@@ -331,10 +350,13 @@ static void nss_cmd_getpwnam_callback(void *ptr, int 
status,
             dctx->res = talloc_steal(dctx, res);
         }
 
-        ret = sss_dp_send_acct_req(cctx->rctx, cmdctx,
-                                   nss_cmd_getpwnam_dp_callback, dctx,
-                                   timeout, dctx->domain->name, SSS_DP_USER,
-                                   cmdctx->name, 0);
+        if (need_callback) {
+            cb = nss_cmd_getpwnam_dp_callback;
+        }
+
+        ret = sss_dp_send_acct_req(cctx->rctx, cmdctx, cb,
+                                   dctx, timeout, dctx->domain->name,
+                                   SSS_DP_USER, cmdctx->name, 0);
         if (ret != EOK) {
             DEBUG(3, ("Failed to dispatch request: %d(%s)\n",
                       ret, strerror(ret)));
@@ -344,7 +366,15 @@ static void nss_cmd_getpwnam_callback(void *ptr, int 
status,
             }
             sss_cmd_done(cctx, cmdctx);
         }
-        return;
+
+        if (need_callback) {
+            return;
+        }
+
+        /* If this was an out-of-band update, continue below to return the
+         * cached value right now.
+         */
+        DEBUG(3, ("Updating cache out-of-band\n"));
     }
 
     switch (res->count) {
@@ -645,12 +675,15 @@ static void nss_cmd_getpwuid_callback(void *ptr, int 
status,
     struct cli_ctx *cctx = cmdctx->cctx;
     struct sss_domain_info *dom;
     struct nss_ctx *nctx;
-    int timeout;
+    int timeout, refresh_timeout;
+    time_t now;
     uint64_t lastUpdate;
     uint8_t *body;
     size_t blen;
     bool call_provider = false;
     bool neghit = false;
+    bool need_callback = true;
+    sss_dp_callback_t cb = NULL;
     int ret;
     int ncret;
 
@@ -668,16 +701,30 @@ static void nss_cmd_getpwuid_callback(void *ptr, int 
status,
     if (dctx->check_provider) {
         switch (res->count) {
         case 0:
+            /* This is a cache miss. We need to get the updated user 
information
+             * before returning it.
+             */
             call_provider = true;
+            need_callback = true;
             break;
 
         case 1:
             timeout = nctx->cache_timeout;
-
+            refresh_timeout = nctx->cache_refresh_timeout;
             lastUpdate = ldb_msg_find_attr_as_uint64(res->msgs[0],
                                                      SYSDB_LAST_UPDATE, 0);
-            if (lastUpdate + timeout < time(NULL)) {
+            now = time(NULL);
+            if (lastUpdate + timeout < now) {
                 call_provider = true;
+                need_callback = true;
+            }
+            else if (refresh_timeout && (lastUpdate + refresh_timeout < now)) {
+                /* We're past the the cache refresh timeout
+                 * We'll return the value from the cache, but we'll also
+                 * queue the cache entry for update out-of-band.
+                 */
+                call_provider = true;
+                need_callback = false;
             }
             break;
 
@@ -703,10 +750,13 @@ static void nss_cmd_getpwuid_callback(void *ptr, int 
status,
             dctx->res = talloc_steal(dctx, res);
         }
 
-        ret = sss_dp_send_acct_req(cctx->rctx, cmdctx,
-                                   nss_cmd_getpwuid_dp_callback, dctx,
-                                   timeout, dctx->domain->name, SSS_DP_USER,
-                                   NULL, cmdctx->id);
+        if (need_callback) {
+            cb = nss_cmd_getpwuid_dp_callback;
+        }
+
+        ret = sss_dp_send_acct_req(cctx->rctx, cmdctx, cb,
+                                   dctx, timeout, dctx->domain->name,
+                                   SSS_DP_USER, NULL, cmdctx->id);
         if (ret != EOK) {
             DEBUG(3, ("Failed to dispatch request: %d(%s)\n",
                       ret, strerror(ret)));
@@ -716,7 +766,14 @@ static void nss_cmd_getpwuid_callback(void *ptr, int 
status,
             }
             sss_cmd_done(cctx, cmdctx);
         }
-        return;
+        if (need_callback) {
+            return;
+        }
+
+        /* If this was an out-of-band update, continue below to return the
+         * cached value right now.
+         */
+        DEBUG(3, ("Updating cache out-of-band\n"));
     }
 
     switch (res->count) {
@@ -1680,12 +1737,15 @@ static void nss_cmd_getgrnam_callback(void *ptr, int 
status,
     struct cli_ctx *cctx = cmdctx->cctx;
     struct sss_domain_info *dom;
     struct nss_ctx *nctx;
-    int timeout;
+    int timeout, refresh_timeout;
+    time_t now;
     uint64_t lastUpdate;
     uint8_t *body;
     size_t blen;
     bool call_provider = false;
     bool neghit = false;
+    bool need_callback = true;
+    sss_dp_callback_t cb = NULL;
     int ncret;
     int ret;
 
@@ -1703,16 +1763,30 @@ static void nss_cmd_getgrnam_callback(void *ptr, int 
status,
     if (dctx->check_provider) {
         switch (res->count) {
         case 0:
+            /* This is a cache miss. We need to get the updated user 
information
+             * before returning it.
+             */
             call_provider = true;
+            need_callback = true;
             break;
 
         default:
             timeout = nctx->cache_timeout;
-
+            refresh_timeout = nctx->cache_refresh_timeout;
             lastUpdate = ldb_msg_find_attr_as_uint64(res->msgs[0],
                                                      SYSDB_LAST_UPDATE, 0);
-            if (lastUpdate + timeout < time(NULL)) {
+            now = time(NULL);
+            if (lastUpdate + timeout < now) {
                 call_provider = true;
+                need_callback = true;
+            }
+            else if (refresh_timeout && (lastUpdate + refresh_timeout < now)) {
+                /* We're past the the cache refresh timeout
+                 * We'll return the value from the cache, but we'll also
+                 * queue the cache entry for update out-of-band.
+                 */
+                call_provider = true;
+                need_callback = false;
             }
         }
     }
@@ -1728,10 +1802,13 @@ static void nss_cmd_getgrnam_callback(void *ptr, int 
status,
             dctx->res = talloc_steal(dctx, res);
         }
 
-        ret = sss_dp_send_acct_req(cctx->rctx, cmdctx,
-                                   nss_cmd_getgrnam_dp_callback, dctx,
-                                   timeout, dctx->domain->name, SSS_DP_GROUP,
-                                   cmdctx->name, 0);
+        if(need_callback) {
+            cb = nss_cmd_getgrnam_dp_callback;
+        }
+
+        ret = sss_dp_send_acct_req(cctx->rctx, cmdctx, cb,
+                                   dctx, timeout, dctx->domain->name,
+                                   SSS_DP_GROUP, cmdctx->name, 0);
         if (ret != EOK) {
             DEBUG(3, ("Failed to dispatch request: %d(%s)\n",
                       ret, strerror(ret)));
@@ -1741,7 +1818,14 @@ static void nss_cmd_getgrnam_callback(void *ptr, int 
status,
             }
             sss_cmd_done(cctx, cmdctx);
         }
-        return;
+
+        if (need_callback) {
+            return;
+        }
+        /* If this was an out-of-band update, continue below to return the
+         * cached value right now.
+         */
+        DEBUG(3, ("Updating cache out-of-band\n"));
     }
 
     switch (res->count) {
@@ -2037,12 +2121,15 @@ static void nss_cmd_getgrgid_callback(void *ptr, int 
status,
     struct cli_ctx *cctx = cmdctx->cctx;
     struct sss_domain_info *dom;
     struct nss_ctx *nctx;
-    int timeout;
+    int timeout, refresh_timeout;
+    time_t now;
     uint64_t lastUpdate;
     uint8_t *body;
     size_t blen;
     bool call_provider = false;
     bool neghit = false;
+    bool need_callback = true;
+    sss_dp_callback_t cb = NULL;
     int ret;
     int ncret;
 
@@ -2060,22 +2147,38 @@ static void nss_cmd_getgrgid_callback(void *ptr, int 
status,
     if (dctx->check_provider) {
         switch (res->count) {
         case 0:
+            /* This is a cache miss. We need to get the updated user 
information
+             * before returning it.
+             */
             call_provider = true;
+            need_callback = true;
             break;
 
         default:
             timeout = nctx->cache_timeout;
-
+            refresh_timeout = nctx->cache_refresh_timeout;
             lastUpdate = ldb_msg_find_attr_as_uint64(res->msgs[0],
                                                      SYSDB_LAST_UPDATE, 0);
-            if (lastUpdate + timeout < time(NULL)) {
+            now = time(NULL);
+            if (lastUpdate + timeout < now) {
+                /* This is a cache miss. We need to get the updated user
+                 * information before returning it.
+                 */
                 call_provider = true;
+                need_callback = true;
+            }
+            else if (refresh_timeout && (lastUpdate + refresh_timeout < now)) {
+                /* We're past the the cache refresh timeout
+                 * We'll return the value from the cache, but we'll also
+                 * queue the cache entry for update out-of-band.
+                 */
+                call_provider = true;
+                need_callback = false;
             }
         }
     }
 
     if (call_provider) {
-
         /* dont loop forever :-) */
         dctx->check_provider = false;
         timeout = SSS_CLI_SOCKET_TIMEOUT/2;
@@ -2085,10 +2188,13 @@ static void nss_cmd_getgrgid_callback(void *ptr, int 
status,
             dctx->res = talloc_steal(dctx, res);
         }
 
-        ret = sss_dp_send_acct_req(cctx->rctx, cmdctx,
-                                   nss_cmd_getgrgid_dp_callback, dctx,
-                                   timeout, dctx->domain->name, SSS_DP_GROUP,
-                                   NULL, cmdctx->id);
+        if(need_callback) {
+            cb = nss_cmd_getgrgid_dp_callback;
+        }
+
+        ret = sss_dp_send_acct_req(cctx->rctx, cmdctx, cb,
+                                   dctx, timeout, dctx->domain->name,
+                                   SSS_DP_GROUP, NULL, cmdctx->id);
         if (ret != EOK) {
             DEBUG(3, ("Failed to dispatch request: %d(%s)\n",
                       ret, strerror(ret)));
@@ -2098,7 +2204,14 @@ static void nss_cmd_getgrgid_callback(void *ptr, int 
status,
             }
             sss_cmd_done(cctx, cmdctx);
         }
-        return;
+
+        if (need_callback) {
+            return;
+        }
+        /* If this was an out-of-band update, continue below to return the
+         * cached value right now.
+         */
+        DEBUG(3, ("Updating cache out-of-band\n"));
     }
 
     switch (res->count) {
@@ -2850,12 +2963,15 @@ static void nss_cmd_getinit_callback(void *ptr, int 
status,
     struct cli_ctx *cctx = cmdctx->cctx;
     struct sss_domain_info *dom;
     struct nss_ctx *nctx;
-    int timeout;
+    int timeout, refresh_timeout;
+    time_t now;
     uint64_t lastUpdate;
     uint8_t *body;
     size_t blen;
     bool call_provider = false;
     bool neghit = false;
+    bool need_callback = true;
+    sss_dp_callback_t cb = NULL;
     int ncret;
     int ret;
 
@@ -2873,16 +2989,33 @@ static void nss_cmd_getinit_callback(void *ptr, int 
status,
     if (dctx->check_provider) {
         switch (res->count) {
         case 0:
+            /* This is a cache miss. We need to get the updated user 
information
+             * before returning it.
+             */
             call_provider = true;
+            need_callback = true;
             break;
 
         case 1:
             timeout = nctx->cache_timeout;
-
+            refresh_timeout = nctx->cache_refresh_timeout;
             lastUpdate = ldb_msg_find_attr_as_uint64(res->msgs[0],
                                                      SYSDB_LAST_UPDATE, 0);
-            if (lastUpdate + timeout < time(NULL)) {
+            now = time(NULL);
+            if (lastUpdate + timeout < now) {
+                /* This is a cache miss. We need to get the updated user
+                 * information before returning it.
+                 */
+                call_provider = true;
+                need_callback = true;
+            }
+            else if (refresh_timeout && (lastUpdate + refresh_timeout < now)) {
+                /* We're past the the cache refresh timeout
+                 * We'll return the value from the cache, but we'll also
+                 * queue the cache entry for update out-of-band.
+                 */
                 call_provider = true;
+                need_callback = false;
             }
             break;
 
@@ -2908,10 +3041,13 @@ static void nss_cmd_getinit_callback(void *ptr, int 
status,
             dctx->res = talloc_steal(dctx, res);
         }
 
-        ret = sss_dp_send_acct_req(cctx->rctx, cmdctx,
-                                   nss_cmd_getinitnam_dp_callback, dctx,
-                                   timeout, dctx->domain->name, SSS_DP_USER,
-                                   cmdctx->name, 0);
+        if (need_callback) {
+            cb = nss_cmd_getinitnam_dp_callback;
+        }
+
+        ret = sss_dp_send_acct_req(cctx->rctx, cmdctx, cb,
+                                   dctx, timeout, dctx->domain->name,
+                                   SSS_DP_USER, cmdctx->name, 0);
         if (ret != EOK) {
             DEBUG(3, ("Failed to dispatch request: %d(%s)\n",
                       ret, strerror(ret)));
@@ -2921,7 +3057,14 @@ static void nss_cmd_getinit_callback(void *ptr, int 
status,
             }
             sss_cmd_done(cctx, cmdctx);
         }
-        return;
+        if (need_callback) {
+            return;
+        }
+
+        /* If this was an out-of-band update, continue below to return the
+         * cached value right now.
+         */
+        DEBUG(3, ("Updating cache out-of-band\n"));
     }
 
     switch (res->count) {
-- 
1.6.2.5

Attachment: signature.asc
Description: OpenPGP digital signature

_______________________________________________
sssd-devel mailing list
[email protected]
https://fedorahosted.org/mailman/listinfo/sssd-devel

Reply via email to