]> andersk Git - moira.git/commitdiff
Remove object id <-> name cache.
authorzacheiss <zacheiss>
Sun, 1 Apr 2001 05:31:11 +0000 (05:31 +0000)
committerzacheiss <zacheiss>
Sun, 1 Apr 2001 05:31:11 +0000 (05:31 +0000)
Stop caching capacl list_id values in check_query_access().

server/Makefile.in
server/cache.pc [deleted file]
server/qfollow.pc
server/qrtn.pc
server/qsupport.pc
server/query.h
server/qvalidate.pc

index d024d3a1b37d1473b4302fae95189330d2e3020d..cd8d1984c3fb99f70886ed1d8ad97d76a99ab728 100644 (file)
@@ -28,12 +28,12 @@ mrbindir=@mrbindir@
 
 SERVER_OBJS=   mr_main.o mr_sauth.o mr_scall.o mr_shutdown.o mr_util.o \
                qvalidate.o qaccess.o qsetup.o qsupport.o qfollow.o \
-               queries2.o qrtn.o qsubs.o increment.o cache.o
+               queries2.o qrtn.o qsubs.o increment.o 
 SCHEMA_OBJS=   ../db/moira_schema.o
 START_OBJS=    startmoira.o
 
 CFILES=                qvalidate.c qaccess.c qsetup.c qsupport.c qfollow.c \
-               qrtn.c increment.c cache.c
+               qrtn.c increment.c
 
 TARGET=moirad startmoira
 
diff --git a/server/cache.pc b/server/cache.pc
deleted file mode 100644 (file)
index 68f5ffe..0000000
+++ /dev/null
@@ -1,401 +0,0 @@
-/* $Id$
- *
- * Keep a cache of name/id mappings
- *
- * Copyright (C) 1989-1998 by the Massachusetts Institute of Technology
- * For copying and distribution information, please see the file
- * <mit-copyright.h>.
- */
-
-#include <mit-copyright.h>
-#include "mr_server.h"
-#include "query.h"
-
-#include <stdlib.h>
-#include <string.h>
-
-EXEC SQL INCLUDE sqlca;
-
-RCSID("$Header$");
-
-EXEC SQL WHENEVER SQLERROR DO dbmserr();
-
-extern char *whoami;
-
-/* Cache parameters: */
-#define CACHESIZE 101          /* number of cache slots */
-
-struct item {
-  char name[MAX_FIELD_WIDTH];
-  enum tables type;
-  int nhash;
-  int id;
-  struct item *next;
-  struct item *prev;
-  struct item *trans;          /* keep track of transactions */
-};
-
-static struct item cachehead;
-static int cachesize;
-
-/* statistics counters */
-int cachehits = 0, cachemisses = 0;
-
-int hashname(char *name, enum tables type);
-
-/* Name hash function. */
-
-int hashname(char *name, enum tables type)
-{
-  int val = type;
-
-  while (*name)
-    val = (val << 5) - val + *name++ - '`';
-  return val;
-}
-
-
-/* Initialize the cache, flushing any old data, and report the statistics
- * if the cache was previously in use.
- */
-
-void flush_cache(void)
-{
-  struct item *i;
-
-  if (cachehits + cachemisses != 0)
-    {
-      com_err(whoami, 0, "Flushing cache; %d hits, %d misses, %d%% hit rate",
-             cachehits, cachemisses,
-             (100 * cachehits) / (cachehits + cachemisses));
-    }
-  else
-    cachehead.next = cachehead.prev = &cachehead;
-  cachehits = cachemisses = cachesize = 0;
-  for (i = cachehead.next; i != &cachehead; i = i->next)
-    {
-      if (i->prev != &cachehead)
-       free(i->prev);
-    }
-  if (cachehead.prev != &cachehead)
-    free(cachehead.prev);
-  cachehead.next = cachehead.prev = &cachehead;
-  cachehead.trans = NULL;
-}
-
-
-/* Do a name to ID translation.  id will be updated with the answer if
- * it is available, and as a side effect the cache is updated.
- */
-
-int name_to_id(char *name, enum tables type, int *id)
-{
-  struct item *i, *t;
-  EXEC SQL BEGIN DECLARE SECTION;
-  char *iname;
-  int j, h;
-  EXEC SQL END DECLARE SECTION;
-
-  h = hashname(name, type);
-  for (i = cachehead.next; i != &cachehead; i = i->next)
-    {
-      if (i->nhash != h || strcmp(name, i->name) || type != i->type)
-       continue;
-      *id = i->id;
-      cachehits++;
-      i->next->prev = i->prev;
-      i->prev->next = i->next;
-      i->next = cachehead.next;
-      i->prev = &cachehead;
-      cachehead.next->prev = i;
-      cachehead.next = i;
-      return MR_SUCCESS;
-    }
-
-  cachemisses++;
-  iname = name;
-
-  switch (type)
-    {
-    case USERS_TABLE:
-      if (strchr(iname, '@') || (strlen(iname) > 8))
-       {
-         sqlca.sqlcode = SQL_NO_MATCH;
-         break;
-       }
-      EXEC SQL SELECT users_id INTO :j FROM users WHERE login = :iname;
-      break;
-    case LIST_TABLE:
-      EXEC SQL SELECT list_id INTO :j FROM list WHERE name = :iname;
-      break;
-    case MACHINE_TABLE:
-      EXEC SQL SELECT mach_id INTO :j FROM machine WHERE name = UPPER(:iname);
-      break;
-    case SUBNET_TABLE:
-      EXEC SQL SELECT snet_id INTO :j FROM subnet WHERE name = UPPER(:iname);
-      break;
-    case CLUSTERS_TABLE:
-      EXEC SQL SELECT clu_id INTO :j FROM clusters WHERE name = :iname;
-      break;
-    case FILESYS_TABLE:
-      EXEC SQL SELECT filsys_id INTO :j FROM filesys WHERE label = :iname;
-      break;
-    case STRINGS_TABLE:
-      if (!iname[0])   /* special-case empty string */
-       {
-         *id = 0;
-         return MR_SUCCESS;
-       }
-      EXEC SQL SELECT string_id INTO :j FROM strings WHERE string = :iname;
-      break;
-    default:
-      return MR_INTERNAL;
-    }
-  if (sqlca.sqlcode == SQL_NO_MATCH)
-    return MR_NO_MATCH;
-  if (sqlca.sqlerrd[2] > 1)
-    return MR_NOT_UNIQUE;
-  if (sqlca.sqlcode)
-    return MR_DBMS_ERR;
-  *id = j;
-  if (name[0] == '#' && type != USERS_TABLE)
-    return MR_SUCCESS;
-  if (cachesize < CACHESIZE)
-    {
-      i = malloc(sizeof(struct item));
-      if (!i)
-       return MR_SUCCESS;
-      cachesize++;
-    }
-  else
-    {
-      i = cachehead.prev;
-      cachehead.prev = i->prev;
-      i->prev->next = &cachehead;
-    }
-  strcpy(i->name, name);
-  i->type = type;
-  i->nhash = h;
-  i->id = j;
-  i->next = cachehead.next;
-  i->prev = &cachehead;
-  i->trans = NULL;
-  cachehead.next->prev = i;
-  cachehead.next = i;
-  /* find the end of the transaction chain & add this item */
-  for (t = &cachehead; t->trans && t != i; t = t->trans)
-    ;
-  if (t != i)
-    t->trans = i;
-  return MR_SUCCESS;
-}
-
-
-/* Perform an ID to name mapping.  name should be a pointer to a pointer to
- * malloc'ed data.  The buffer it refers to will be freed, and a new buffer
- * allocated with the answer.
- */
-
-int id_to_name(int id, enum tables type, char **name)
-{
-  struct item *i, *t;
-  EXEC SQL BEGIN DECLARE SECTION;
-  char iname[MAX_FIELD_WIDTH];
-  int j;
-  EXEC SQL END DECLARE SECTION;
-
-  for (i = cachehead.next; i != &cachehead; i = i->next)
-    {
-      if (i->id != id || type != i->type)
-       continue;
-      free(*name);
-      *name = xstrdup(i->name);
-      cachehits++;
-      i->next->prev = i->prev;
-      i->prev->next = i->next;
-      i->next = cachehead.next;
-      i->prev = &cachehead;
-      cachehead.next->prev = i;
-      cachehead.next = i;
-      return MR_SUCCESS;
-    }
-
-  cachemisses++;
-  j = id;
-
-  switch (type)
-    {
-    case USERS_TABLE:
-      EXEC SQL SELECT login INTO :iname FROM users WHERE users_id = :j;
-      break;
-    case LIST_TABLE:
-      EXEC SQL SELECT name INTO :iname FROM list WHERE list_id = :j;
-      break;
-    case MACHINE_TABLE:
-      EXEC SQL SELECT name INTO :iname FROM machine WHERE mach_id = :j;
-      break;
-    case SUBNET_TABLE:
-      EXEC SQL SELECT name INTO :iname FROM subnet WHERE snet_id = :j;
-      break;
-    case CLUSTERS_TABLE:
-      EXEC SQL SELECT name INTO :iname FROM clusters WHERE clu_id = :j;
-      break;
-    case FILESYS_TABLE:
-      EXEC SQL SELECT label INTO :iname FROM filesys WHERE filsys_id = :j;
-      break;
-    case STRINGS_TABLE:
-      EXEC SQL SELECT string INTO :iname FROM strings WHERE string_id = :j;
-      break;
-    default:
-      return MR_INTERNAL;
-    }
-  if (sqlca.sqlcode == SQL_NO_MATCH)
-    {
-      free(*name);
-      sprintf(iname, "#%d", j);
-      *name = xstrdup(iname);
-      return MR_NO_MATCH;
-    }
-  if (sqlca.sqlerrd[2] > 1)
-    return MR_INTERNAL;
-  if (sqlca.sqlcode)
-    return MR_DBMS_ERR;
-  free(*name);
-  *name = xstrdup(strtrim(iname));
-  if (**name == '#' && type != USERS_TABLE)
-    return MR_SUCCESS;
-  if (cachesize < CACHESIZE)
-    {
-      i = malloc(sizeof(struct item));
-      if (!i)
-       return MR_SUCCESS;
-      cachesize++;
-    }
-  else
-    {
-      i = cachehead.prev;
-      cachehead.prev = i->prev;
-      i->prev->next = &cachehead;
-    }
-  strcpy(i->name, *name);
-  i->type = type;
-  i->nhash = hashname(*name, type);
-  i->id = id;
-  i->next = cachehead.next;
-  i->prev = &cachehead;
-  i->trans = NULL;
-  cachehead.next->prev = i;
-  cachehead.next = i;
-  /* find the end of the transaction chain & add this item */
-  for (t = &cachehead; t->trans && t != i; t = t->trans)
-    ;
-  if (t != i)
-    t->trans = i;
-  return MR_SUCCESS;
-}
-
-
-/* Explicitly add something to the cache without doing a lookup in the
- * database.
- */
-
-int cache_entry(char *name, enum tables type, int id)
-{
-  struct item *i, *t;
-
-  for (i = cachehead.next; i != &cachehead; i = i->next)
-    {
-      if (i->id == id && i->type == type)
-       {
-         if (strcmp(i->name, name))
-           {
-             strcpy(i->name, name);
-             i->nhash = hashname(name, type);
-           }
-         return MR_SUCCESS;
-       }
-    }
-  if (cachesize < CACHESIZE)
-    {
-      i = malloc(sizeof(struct item));
-      if (!i)
-       return MR_SUCCESS;
-      cachesize++;
-    }
-  else
-    {
-      i = cachehead.prev;
-      cachehead.prev = i->prev;
-      i->prev->next = &cachehead;
-    }
-  strcpy(i->name, name);
-  i->type = type;
-  i->nhash = hashname(name, type);
-  i->id = id;
-  i->next = cachehead.next;
-  i->prev = &cachehead;
-  i->trans = NULL;
-  cachehead.next->prev = i;
-  cachehead.next = i;
-  /* find the end of the transaction chain & add this item */
-  for (t = &cachehead; t->trans && t != i; t = t->trans)
-    ;
-  if (t != i)
-    t->trans = i;
-  return MR_SUCCESS;
-}
-
-
-/* Flush something that may or may not already be in the cache. */
-
-void flush_name(char *name, enum tables type)
-{
-  struct item *i;
-
-  /* first clear it out of the transaction chain */
-  for (i = &cachehead; i && i->trans; i = i->trans)
-    {
-      if (!strcmp(name, i->trans->name) && type == i->trans->type)
-       i->trans = i->trans->trans;
-    }
-
-  /* now remove it */
-  for (i = cachehead.next; i != &cachehead; i = i->next)
-    {
-      if (!strcmp(name, i->name) && type == i->type)
-       {
-         cachesize--;
-         i->next->prev = i->prev;
-         i->prev->next = i->next;
-         free(i);
-         break;
-       }
-    }
-}
-
-
-/* Called when a transaction is committed to also commit any cache changes.
- * Just throws away the list of cache changes for this transaction.
- */
-
-void cache_commit(void)
-{
-  cachehead.trans = NULL;
-}
-
-
-/* Called whan a transaction is aborted to throw away any cache changes
- * from that transaction.
- */
-
-void cache_abort(void)
-{
-  struct item *i, *t;
-
-  for (i = cachehead.trans; i; i = t)
-    {
-      t = i->trans;
-      flush_name(i->name, i->type);
-    }
-  cachehead.trans = NULL;
-}
index feff14893ceb17f7b6a62029534b13b98e31741e..ac6cb510da7fb03a93ce32fe866e5bc0f125a524 100644 (file)
@@ -812,7 +812,6 @@ int followup_aqot(struct query *q, char *argv[], client *cl)
 
   if (dbms_errno)
     return mr_errcode;
-  flush_name(argv[0], table);
   if (q->type == APPEND)
     {
       EXEC SQL UPDATE tblstats SET appends = appends + 1, modtime = SYSDATE
@@ -877,7 +876,6 @@ int followup_dqot(struct query *q, char **argv, client *cl)
 
   if (dbms_errno)
     return mr_errcode;
-  flush_name(argv[0], table);
 
   EXEC SQL UPDATE tblstats SET deletes = deletes + 1, modtime = SYSDATE
     WHERE table_name = :tname;
index 3553c955a803530d27b59f972927b44cc9d15ce2..cfcd0226643c8de446dcf881b841621718dbb6f0 100644 (file)
@@ -101,7 +101,6 @@ int mr_open_database(void)
       mr_sqlda = mr_alloc_sqlda();
 
       incremental_init();
-      flush_cache();
     }
 
   dbms_errno = 0;
@@ -123,7 +122,6 @@ int mr_open_database(void)
 
 void mr_close_database(void)
 {
-  flush_cache();
   EXEC SQL COMMIT RELEASE;
 }
 
@@ -266,7 +264,6 @@ int mr_process_query(client *cl, char *name, int argc, char *argv_ro[],
          incremental_after(q->rtable, qual, argv_ro);
          if (status != MR_SUCCESS)
            break;
-         flush_name(argv_ro[0], q->rtable);
          table = table_name[q->rtable];
          if (strcmp(q->shortname, "sshi") && strcmp(q->shortname, "ssif"))
            {
@@ -345,7 +342,6 @@ int mr_process_query(client *cl, char *name, int argc, char *argv_ro[],
          incremental_clear_after();
          if (status != MR_SUCCESS)
            break;
-         flush_name(argv_ro[0], q->rtable);
          EXEC SQL UPDATE tblstats
            SET deletes = deletes + 1, modtime = SYSDATE
            WHERE table_name = :table;
@@ -401,12 +397,10 @@ out:
        }
       else
        {
-         cache_abort();
          EXEC SQL ROLLBACK WORK;
          incremental_flush();
        }
     }
-  cache_commit(); /* commit following abort is safe */
 
   if (status != MR_SUCCESS)
     com_err(whoami, status, " (Query failed)");
@@ -600,11 +594,6 @@ int mr_verify_query(client *cl, struct query *q, int argc, char *argv_ro[])
   return privileged ? MR_SUCCESS : MR_PERM;
 }
 
-
-/* This routine caches info from the database.  Each query acl is stored
- * in the query structure, and whether that acl contains everybody.
- */
-
 int check_query_access(struct query *q, char *argv[], client *cl)
 {
   EXEC SQL BEGIN DECLARE SECTION;
@@ -617,28 +606,22 @@ int check_query_access(struct query *q, char *argv[], client *cl)
   if (def_uid == 0)
     EXEC SQL SELECT users_id INTO :def_uid FROM users WHERE login = 'default';
 
-  /* get query access control list */
-  if (q->acl != 0)
-    acl_id = q->acl;
+  name = q->shortname;
+  EXEC SQL SELECT list_id INTO :acl_id FROM capacls WHERE tag = :name;
+  if (sqlca.sqlcode < 0)
+    return MR_DBMS_ERR;
+  if (sqlca.sqlcode == SQL_NO_MATCH)
+    return MR_PERM;
+  q->acl = acl_id;
+  
+  /* check for default access */
+  EXEC SQL SELECT member_id INTO :acl_id FROM imembers
+    WHERE list_id = :acl_id AND member_type = 'USER'
+    AND member_id = :def_uid;
+  if (sqlca.sqlerrd[2] == 0)
+    q->everybody = 0;
   else
-    {
-      name = q->shortname;
-      EXEC SQL SELECT list_id INTO :acl_id FROM capacls WHERE tag = :name;
-      if (sqlca.sqlcode < 0)
-       return MR_DBMS_ERR;
-      if (sqlca.sqlcode == SQL_NO_MATCH)
-       return MR_PERM;
-      q->acl = acl_id;
-
-      /* check for default access */
-      EXEC SQL SELECT member_id INTO :acl_id FROM imembers
-       WHERE list_id = :acl_id AND member_type = 'USER'
-       AND member_id = :def_uid;
-      if (sqlca.sqlerrd[2] == 0)
-       q->everybody = 0;
-      else
-       q->everybody = 1;
-    }
+    q->everybody = 1;
 
   if (q->everybody)
     return MR_SUCCESS;
@@ -981,5 +964,124 @@ int do_for_all_rows(char *query, int count,
     return MR_SUCCESS;
 }
 
+/* Do a name to ID translation.  Moved from cache.pc because we did away
+ * with the cache, but what this function does is still useful to us.
+ */
+
+int name_to_id(char *name, enum tables type, int *id)
+{
+  EXEC SQL BEGIN DECLARE SECTION;
+  char *iname;
+  int j;
+  EXEC SQL END DECLARE SECTION;
+
+  iname = name;
+
+  switch (type)
+    {
+    case USERS_TABLE:
+      if (strchr(iname, '@') || (strlen(iname) > 8))
+       {
+         sqlca.sqlcode = SQL_NO_MATCH;
+         break;
+       }
+      EXEC SQL SELECT users_id INTO :j FROM users WHERE login = :iname;
+      break;
+    case LIST_TABLE:
+      EXEC SQL SELECT list_id INTO :j FROM list WHERE name = :iname;
+      break;
+    case MACHINE_TABLE:
+      EXEC SQL SELECT mach_id INTO :j FROM machine WHERE name = UPPER(:iname);
+      break;
+    case SUBNET_TABLE:
+      EXEC SQL SELECT snet_id INTO :j FROM subnet WHERE name = UPPER(:iname);
+      break;
+    case CLUSTERS_TABLE:
+      EXEC SQL SELECT clu_id INTO :j FROM clusters WHERE name = :iname;
+      break;
+    case FILESYS_TABLE:
+      EXEC SQL SELECT filsys_id INTO :j FROM filesys WHERE label = :iname;
+      break;
+    case STRINGS_TABLE:
+      if (!iname[0])   /* special-case empty string */
+       {
+         *id = 0;
+         return MR_SUCCESS;
+       }
+      EXEC SQL SELECT string_id INTO :j FROM strings WHERE string = :iname;
+      break;
+    default:
+      return MR_INTERNAL;
+    }
+  if (sqlca.sqlcode == SQL_NO_MATCH)
+    return MR_NO_MATCH;
+  if (sqlca.sqlerrd[2] > 1)
+    return MR_NOT_UNIQUE;
+  if (sqlca.sqlcode)
+    return MR_DBMS_ERR;
+  *id = j;
+
+  return MR_SUCCESS;
+}
+
+/* Perform an ID to name mapping.  name should be a pointer to a pointer to
+ * malloc'ed data.  The buffer it refers to will be freed, and a new buffer
+ * allocated with the answer.
+ * 
+ * This used to be in cache.pc, but we've removed the cache, and this function 
+ * is still useful to us.
+ */
+
+int id_to_name(int id, enum tables type, char **name)
+{
+  EXEC SQL BEGIN DECLARE SECTION;
+  char iname[MAX_FIELD_WIDTH];
+  int j;
+  EXEC SQL END DECLARE SECTION;
+
+  j = id;
+
+  switch (type)
+    {
+    case USERS_TABLE:
+      EXEC SQL SELECT login INTO :iname FROM users WHERE users_id = :j;
+      break;
+    case LIST_TABLE:
+      EXEC SQL SELECT name INTO :iname FROM list WHERE list_id = :j;
+      break;
+    case MACHINE_TABLE:
+      EXEC SQL SELECT name INTO :iname FROM machine WHERE mach_id = :j;
+      break;
+    case SUBNET_TABLE:
+      EXEC SQL SELECT name INTO :iname FROM subnet WHERE snet_id = :j;
+      break;
+    case CLUSTERS_TABLE:
+      EXEC SQL SELECT name INTO :iname FROM clusters WHERE clu_id = :j;
+      break;
+    case FILESYS_TABLE:
+      EXEC SQL SELECT label INTO :iname FROM filesys WHERE filsys_id = :j;
+      break;
+    case STRINGS_TABLE:
+      EXEC SQL SELECT string INTO :iname FROM strings WHERE string_id = :j;
+      break;
+    default:
+      return MR_INTERNAL;
+    }
+  if (sqlca.sqlcode == SQL_NO_MATCH)
+    {
+      free(*name);
+      sprintf(iname, "#%d", j);
+      *name = xstrdup(iname);
+      return MR_NO_MATCH;
+    }
+  if (sqlca.sqlerrd[2] > 1)
+    return MR_INTERNAL;
+  if (sqlca.sqlcode)
+    return MR_DBMS_ERR;
+  free(*name);
+  *name = xstrdup(strtrim(iname));
+
+  return MR_SUCCESS;
+}
 
 /* eof:qrtn.dc */
index 24d65f6cc91a3bece7303b0850596d16ae72d50c..40250f326ecb499b1cbe80e23084c9b37ae09c79 100644 (file)
@@ -1642,10 +1642,6 @@ int register_user(struct query *q, char **argv, client *cl)
   com_err(whoami, 0, "set login name to %s", login);
   incremental_after(USERS_TABLE, buffer, 0);
 
-  /* We've just changed the login name in the DB; recache it in case
-     the wrong thing got into the cache earlier. */
-  cache_entry(login, USERS_TABLE, users_id);
-
   /* create filesystem */
   if (set_next_object_id("filsys_id", FILESYS_TABLE, 0))
     return MR_NO_ID;
index 1f060d6d2fede1ce5c485d966d5e991b3eb62d47..d193c78ab60ee002a770d1fbdfebd2dd7dd0a895 100644 (file)
@@ -65,16 +65,6 @@ struct valobj
   int error;
 };
 
-
-/* prototypes from cache.dc */
-void flush_cache(void);
-int name_to_id(char *name, enum tables type, int *id);
-int id_to_name(int id, enum tables type, char **name);
-int cache_entry(char *name, enum tables type, int id);
-void flush_name(char *name, enum tables type);
-void cache_commit(void);
-void cache_abort(void);
-
 /* prototypes from increment.dc */
 void incremental_before(enum tables table, char *qualx, char **argv);
 void incremental_clear_before(void);
@@ -84,6 +74,8 @@ void incremental_clear_after(void);
 /* prototypes from qrtn.dc */
 int check_query_access(struct query *q, char *argv[], client *cl);
 int set_next_object_id(char *objectx, enum tables table, int limit);
+int name_to_id(char *name, enum tables type, int *id);
+int id_to_name(int id, enum tables type, char **name);
 
 /* prototypes from qsubs.c */
 void list_queries(client *cl, int (*action)(int, char *[], void *),
index f9500511693166aade4db91759af0674eedefab4..f84b15da236910831d90289bac96dcbdb12137ed 100644 (file)
@@ -209,7 +209,6 @@ int validate_id(struct query *q, char *argv[], struct valobj *vo)
       if (strlen(name) >= STRINGS_STRING_SIZE)
        return MR_ARG_TOO_LONG;
       id = add_string(name);
-      cache_entry(name, STRINGS_TABLE, id);
       *(int *)argv[vo->index] = id;
       return MR_EXISTS;
     }
@@ -417,7 +416,6 @@ int validate_typedata(struct query *q, char *argv[], struct valobj *vo)
          if (strlen(name) >= STRINGS_STRING_SIZE)
            return MR_ARG_TOO_LONG;
          id = add_string(name);
-         cache_entry(name, STRINGS_TABLE, id);
        }
       else if (status)
        return status;
This page took 0.079568 seconds and 5 git commands to generate.