From cee1b1fd99d44f3f2d9aa4d6e6d66c0cebd3797f Mon Sep 17 00:00:00 2001
From: "thek@adventure.(none)" <>
Date: Tue, 18 Mar 2008 10:45:36 +0100
Subject: [PATCH] Bug#25175 Too much memory used by MySQL grant system

Each time the server reloads privileges containing table grants, the
system will allocate too much memory than needed because of badly
chosen growth prediction in the underlying dynamic arrays.

This patch introduces a new signature to the hash container initializer
which enables a much more pessimistic approach in favour for more
efficient memory useage.

This patch was supplied by Google Inc.
---
 include/hash.h | 7 ++++---
 mysys/hash.c   | 5 +++--
 sql/sql_acl.cc | 4 ++--
 3 files changed, 9 insertions(+), 7 deletions(-)

diff --git a/include/hash.h b/include/hash.h
index d924e62a0ec..4ca8dc0e8bf 100644
--- a/include/hash.h
+++ b/include/hash.h
@@ -47,8 +47,9 @@ typedef struct st_hash {
 /* A search iterator state */
 typedef uint HASH_SEARCH_STATE;
 
-#define hash_init(A,B,C,D,E,F,G,H) _hash_init(A,B,C,D,E,F,G, H CALLER_INFO)
-my_bool _hash_init(HASH *hash, CHARSET_INFO *charset,
+#define hash_init(A,B,C,D,E,F,G,H) _hash_init(A,0,B,C,D,E,F,G,H CALLER_INFO)
+#define hash_init2(A,B,C,D,E,F,G,H,I) _hash_init(A,B,C,D,E,F,G,H,I CALLER_INFO)
+my_bool _hash_init(HASH *hash, uint growth_size,CHARSET_INFO *charset,
 		   ulong default_array_elements, size_t key_offset,
 		   size_t key_length, hash_get_key get_key,
 		   void (*free_element)(void*), uint flags CALLER_INFO_PROTO);
@@ -69,7 +70,7 @@ my_bool hash_check(HASH *hash);			/* Only in debug library */
 #define hash_clear(H) bzero((char*) (H),sizeof(*(H)))
 #define hash_inited(H) ((H)->array.buffer != 0)
 #define hash_init_opt(A,B,C,D,E,F,G,H) \
-          (!hash_inited(A) && _hash_init(A,B,C,D,E,F,G, H CALLER_INFO))
+          (!hash_inited(A) && _hash_init(A,0,B,C,D,E,F,G, H CALLER_INFO))
 
 #ifdef	__cplusplus
 }
diff --git a/mysys/hash.c b/mysys/hash.c
index 4532b06b533..9166ae6f788 100644
--- a/mysys/hash.c
+++ b/mysys/hash.c
@@ -46,7 +46,7 @@ static uint calc_hash(const HASH *hash, const uchar *key, size_t length)
 }
 
 my_bool
-_hash_init(HASH *hash,CHARSET_INFO *charset,
+_hash_init(HASH *hash,uint growth_size, CHARSET_INFO *charset,
 	   ulong size, size_t key_offset, size_t key_length,
 	   hash_get_key get_key,
 	   void (*free_element)(void*),uint flags CALLER_INFO_PROTO)
@@ -55,7 +55,8 @@ _hash_init(HASH *hash,CHARSET_INFO *charset,
   DBUG_PRINT("enter",("hash: 0x%lx  size: %u", (long) hash, (uint) size));
 
   hash->records=0;
-  if (my_init_dynamic_array_ci(&hash->array,sizeof(HASH_LINK),size,0))
+  if (my_init_dynamic_array_ci(&hash->array, sizeof(HASH_LINK), size,
+                               growth_size))
   {
     hash->free=0;				/* Allow call to hash_free */
     DBUG_RETURN(1);
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 3805d9fa8b6..9a218395721 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -2281,7 +2281,7 @@ GRANT_TABLE::GRANT_TABLE(const char *h, const char *d,const char *u,
                 	 const char *t, ulong p, ulong c)
   :GRANT_NAME(h,d,u,t,p), cols(c)
 {
-  (void) hash_init(&hash_columns,system_charset_info,
+  (void) hash_init2(&hash_columns,4,system_charset_info,
                    0,0,0, (hash_get_key) get_key_column,0,0);
 }
 
@@ -2329,7 +2329,7 @@ GRANT_TABLE::GRANT_TABLE(TABLE *form, TABLE *col_privs)
   cols= (ulong) form->field[7]->val_int();
   cols =  fix_rights_for_column(cols);
 
-  (void) hash_init(&hash_columns,system_charset_info,
+  (void) hash_init2(&hash_columns,4,system_charset_info,
                    0,0,0, (hash_get_key) get_key_column,0,0);
   if (cols)
   {
-- 
2.30.9