]> git.ipfire.org Git - thirdparty/make.git/commitdiff
* strcache.c: [SV 45275] Handle very long strings.
authorPaul Smith <psmith@gnu.org>
Sat, 11 Jul 2015 21:21:22 +0000 (17:21 -0400)
committerPaul Smith <psmith@gnu.org>
Sun, 12 Jul 2015 04:14:19 +0000 (00:14 -0400)
Our previous behavior for handling too-long strings involved
increasing the size of the default string cache buffer, but the
implementation was incomplete.  Instead, create a one-off large
string cache entry and add it directly to the full cache list
without changing the default buffer size.

makeint.h
strcache.c

index 343c30d21a0a8d33a8c23caa9b0c4224dc18a737..92cf033bf3bc7b32f92cb43ccb2a1ad4ebc732a9 100644 (file)
--- a/makeint.h
+++ b/makeint.h
@@ -542,7 +542,6 @@ void strcache_print_stats (const char *prefix);
 int strcache_iscached (const char *str);
 const char *strcache_add (const char *str);
 const char *strcache_add_len (const char *str, unsigned int len);
-int strcache_setbufsize (unsigned int size);
 
 /* Guile support  */
 int guile_gmake_setup (const gmk_floc *flocp);
index 1ade5e7d914046430afaa1c20fdcd6d1a34e9a94..5cce135901ed46f8aae0cba715fc1f530a80b003 100644 (file)
@@ -42,8 +42,8 @@ struct strcache {
 #define CACHE_BUFFER_ALLOC(_s)  ((_s) - (2 * sizeof (size_t)))
 #define CACHE_BUFFER_OFFSET     (offsetof (struct strcache, buffer))
 #define CACHE_BUFFER_SIZE(_s)   (CACHE_BUFFER_ALLOC(_s) - CACHE_BUFFER_OFFSET)
+#define BUFSIZE                 CACHE_BUFFER_SIZE (CACHE_BUFFER_BASE)
 
-static sc_buflen_t bufsize = CACHE_BUFFER_SIZE (CACHE_BUFFER_BASE);
 static struct strcache *strcache = NULL;
 static struct strcache *fullcache = NULL;
 
@@ -57,62 +57,73 @@ static unsigned long total_size = 0;
    that this doesn't seem to be much of an issue in practice.
  */
 static struct strcache *
-new_cache ()
+new_cache (struct strcache **head, sc_buflen_t buflen)
 {
-  struct strcache *new;
-  new = xmalloc (bufsize + CACHE_BUFFER_OFFSET);
+  struct strcache *new = xmalloc (buflen + CACHE_BUFFER_OFFSET);
   new->end = 0;
   new->count = 0;
-  new->bytesfree = bufsize;
+  new->bytesfree = buflen;
 
-  new->next = strcache;
-  strcache = new;
+  new->next = *head;
+  *head = new;
 
   ++total_buffers;
   return new;
 }
 
+static const char *
+copy_string (struct strcache *sp, const char *str, unsigned int len)
+{
+  /* Add the string to this cache.  */
+  char *res = &sp->buffer[sp->end];
+
+  memmove (res, str, len);
+  res[len++] = '\0';
+  sp->end += len;
+  sp->bytesfree -= len;
+  ++sp->count;
+
+  return res;
+}
+
 static const char *
 add_string (const char *str, unsigned int len)
 {
-  char *res;
+  const char *res;
   struct strcache *sp;
   struct strcache **spp = &strcache;
   /* We need space for the nul char.  */
   unsigned int sz = len + 1;
 
+  ++total_strings;
+  total_size += sz;
+
   /* If the string we want is too large to fit into a single buffer, then
-     no existing cache is large enough.  Change the maximum size.  */
-  if (sz > bufsize)
-    bufsize = CACHE_BUFFER_SIZE ((((sz + 1) / CACHE_BUFFER_BASE) + 1)
-                                 * CACHE_BUFFER_BASE);
-  else
-    /* Find the first cache with enough free space.  */
-    for (; *spp != NULL; spp = &(*spp)->next)
-      if ((*spp)->bytesfree > sz)
-        break;
-
-  /* If nothing is big enough, make a new cache.  */
+     no existing cache is large enough.  Add it directly to the fullcache.  */
+  if (sz > BUFSIZE)
+    {
+      sp = new_cache (&fullcache, sz);
+      return copy_string (sp, str, len);
+    }
+
+  /* Find the first cache with enough free space.  */
+  for (; *spp != NULL; spp = &(*spp)->next)
+    if ((*spp)->bytesfree > sz)
+      break;
+
+  /* If nothing is big enough, make a new cache at the front.  */
   sp = *spp;
   if (sp == NULL)
     {
-      sp = new_cache ();
+      sp = new_cache (&strcache, BUFSIZE);
       spp = &sp;
     }
 
   /* Add the string to this cache.  */
-  res = &sp->buffer[sp->end];
-  memmove (res, str, len);
-  res[len] = '\0';
-  sp->end += sz;
-  sp->bytesfree -= sz;
-  ++sp->count;
+  res = copy_string (sp, str, len);
 
   /* If the amount free in this cache is less than the average string size,
      consider it full and move it to the full list.  */
-  ++total_strings;
-  total_size += sz;
-
   if (sp->bytesfree < (total_size / total_strings) + 1)
     {
       *spp = (*spp)->next;
@@ -207,14 +218,6 @@ strcache_add_len (const char *str, unsigned int len)
   return add_hash (str, len);
 }
 
-int
-strcache_setbufsize (unsigned int size)
-{
-  if (size > bufsize)
-    bufsize = size;
-  return bufsize;
-}
-
 void
 strcache_init (void)
 {
@@ -229,7 +232,7 @@ strcache_print_stats (const char *prefix)
 {
   const struct strcache *sp;
   unsigned long numbuffs = 0, fullbuffs = 0;
-  unsigned long totfree = 0, maxfree = 0, minfree = bufsize;
+  unsigned long totfree = 0, maxfree = 0, minfree = BUFSIZE;
 
   if (! strcache)
     {
@@ -268,12 +271,13 @@ strcache_print_stats (const char *prefix)
           (total_size / total_strings));
 
   printf (_("%s current buf: size = %hu B / used = %hu B / count = %hu / avg = %hu B\n"),
-          prefix, bufsize, strcache->end, strcache->count,
+          prefix, (sc_buflen_t)BUFSIZE, strcache->end, strcache->count,
           (strcache->end / strcache->count));
 
   if (numbuffs)
     {
-      unsigned long sz = total_size - bufsize;
+      /* Show information about non-current buffers.  */
+      unsigned long sz = total_size - strcache->end;
       unsigned long cnt = total_strings - strcache->count;
       sc_buflen_t avgfree = totfree / numbuffs;