[PATCH] PR25628: Debuginfod client should cache negative results.

Mark Wielaard mark@klomp.org
Sat May 1 23:29:49 GMT 2021


Hi Alice,

On Wed, Apr 28, 2021 at 08:10:49AM -0400, Alice Zhang via Elfutils-devel wrote:
> * debuginfod/debuginfod-client.c:
>   - add debuginfod_config_cache for reading and writing to cache
>     configuration files, make use of the function within
>     debuginfod_clean_cache and debuginfod_query_server.
>   - in debuginfod_query_server, create 000-permission file on failed
>     queries. Before querying each BUILDID, if corresponding 000 file
>     detected, compare its stat mtime with parameter from
>     .cache/cache_miss_s. if mtime is fresher, then return ENOENT and
>     exit; otherwise unlink the 000 file and proceed to a new query.

I like the idea.

> diff --git a/ChangeLog b/ChangeLog
> index e18746fb..3c6f5cc0 100644
> --- a/ChangeLog
> +++ b/ChangeLog
> @@ -1,3 +1,7 @@
> +2021-04-28  Alice Zhang  <azhang@redhat.com>
> +        * debuginfod/debuginfod-client.c: Make client able to cache negative
> +	results.
> +	* tests/run-debuginfod-find.sh: Added tests for the feature.

Normally ChangeLog entries go into the ChangeLog files in the
subdirectories.

>  2021-03-30  Frank Ch. Eigler  <fche@redhat.com>
>  
>  	* configure.ac: Look for pthread_setname_np.
> diff --git a/NEWS b/NEWS
> index 038c6019..6d652696 100644
> --- a/NEWS
> +++ b/NEWS
> @@ -2,6 +2,15 @@ Version 0.184
>  
>  debuginfod: Use libarchive's bsdtar as the .deb-family file unpacker.
>  
> +debuginfod-client: Now client would cache negative results. When a
> +                   query fails with 404, a 000-permission file is
> +                   created. When query for a buildid, check whether
> +                   such 000-permission file exists in the cache. If
> +                   so, check its mtime: if mtime is older than the
> +                   parameter from .cache/cache_miss_s, unlink the
> +                   000 file and proceed to a new query; otherwise
> +                   return an -ENOENT.

This is good as commit message, for NEWS try to summarize in one or
two sentences.

> +/* handle config file read and write */
> +static int
> +debuginfod_config_cache(char *config_path,
> +                       long cache_config_default_s)
> +{
> +  int fd;
> +  struct stat st;
> +  /* if the config file doesn't exist, create one with DEFFILEMODE*/
> +  if(stat(config_path, &st) == -1)
> +    {
> +      fd = open(config_path, O_CREAT | O_RDWR, DEFFILEMODE);
> +      if (fd < 0)
> +        return -errno;
> +
> +      if (dprintf(fd, "%ld", cache_config_default_s) < 0)
> +        return -errno;
> +    }
> +
> +  long cache_config;
> +  FILE *config_file = fopen(config_path, "r");
> +  if (config_file)
> +    {
> +      if (fscanf(config_file, "%ld", &cache_config) != 1)
> +        cache_config = cache_config_default_s;
> +      fclose(config_file);
> +    }
> +  else
> +    cache_config = cache_config_default_s;
> +
> +  return cache_config;
> +}

Good idea to generalize this in a new function.  I would suggest to
add a struct stat &st argument so the caller gets the struct stat
result, because...

> +  stat(interval_path, &st);
>    if (time(NULL) - st.st_mtime < clean_interval)
>      /* Interval has not passed, skip cleaning.  */
>      return 0;

Then you can simply use it here ^

> @@ -690,6 +704,24 @@ debuginfod_query_server (debuginfod_client *c,
>        goto out;
>      }

The code ^ tries to open the target_cache_path file.  I think it would
be good to put the below in inside and else branch that checks whether
the open failed with EACCESS, so you know it is a 0000 mode file.

     else if (errno == EACCES)
       {

> +  struct stat st;
> +  time_t cache_miss;
> +  if (stat(target_cache_path, &st) == 0)

And although a race is unlikely, it could be some other client
happened to have created/replaced the file (less likely if you add the
EACCES check). So it would be good to check st.st_mode & 0777 == 0.

> +    {
> +      rc = debuginfod_config_cache(cache_miss_path, cache_miss_default_s);
> +      if (rc < 0)
> +        goto out;
> +
> +      cache_miss = (time_t)rc;
> +      if (time(NULL) - st.st_mtime <= cache_miss)
> +        {
> +         rc = -ENOENT;
> +         goto out;
> +       }
> +      else
> +        unlink(target_cache_path);
> +    }
> +
[...]
> +  /* create a 000-permission file named as $HOME/.cache
> +   * if the query fails with ENOENT.*/
> +  if (rc == -ENOENT)
> +    {
> +      int efd = open (target_cache_path, O_CREAT|O_TRUNC, 0000);
> +      if (efd >= 0)
> +        close(efd);
> +    }

Do we want O_TRUNC here? Doesn't that risk truncating an existing
file? Maybe use O_CREAT|O_EXCL?

Thanks,

Mark


More information about the Elfutils-devel mailing list