From 548413824b85fa0550c8d9a297546b80ed1643e1 Mon Sep 17 00:00:00 2001
From: Kristofer Pettersson <kpettersson@mysql.com>
Date: Thu, 24 Jul 2008 22:38:44 +0200
Subject: [PATCH] Bug#38002 table_cache consumes too much memory with blobs

Tables in the table definition cache are keeping a cache buffer for blob
fields which can consume a lot of memory.

This patch introduces a maximum size threshold for these buffers.


sql/sql_base.cc:
  Added function free_field_buffers_larger_than to reclaim memory from blob
  field buffers too large to be cached.
sql/table.cc:
  Added function free_field_buffers_larger_than
---
 sql/field.h      |  2 +-
 sql/mysql_priv.h |  1 +
 sql/sql_base.cc  |  2 ++
 sql/table.cc     | 22 ++++++++++++++++++++++
 sql/table.h      |  3 +++
 5 files changed, 29 insertions(+), 1 deletion(-)

diff --git a/sql/field.h b/sql/field.h
index 7d312dbd2b8..8e00cf013dc 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -13,7 +13,6 @@
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 
-
 /*
   Because of the function new_field() all field classes that have static
   variables must declare the size_of() member function.
@@ -1669,6 +1668,7 @@ class Field_blob :public Field_longstr {
   }
   int reset(void) { bzero(ptr, packlength+sizeof(uchar*)); return 0; }
   void reset_fields() { bzero((uchar*) &value,sizeof(value)); }
+  uint32 get_field_buffer_size(void) { return value.alloced_length(); }
 #ifndef WORDS_BIGENDIAN
   static
 #endif
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index e150ffd18f8..f6ba5fc9739 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -2130,6 +2130,7 @@ int writefrm(const char* name, const uchar* data, size_t len);
 int closefrm(TABLE *table, bool free_share);
 int read_string(File file, uchar* *to, size_t length);
 void free_blobs(TABLE *table);
+void free_field_buffers_larger_than(TABLE *table, uint32 size);
 int set_zone(int nr,int min_zone,int max_zone);
 ulong convert_period_to_month(ulong period);
 ulong convert_month_to_period(ulong month);
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index d25057789ac..39dd815e738 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -1369,6 +1369,8 @@ bool close_thread_table(THD *thd, TABLE **table_ptr)
     DBUG_ASSERT(!table->is_children_attached());
 
     /* Free memory and reset for next loop */
+    free_field_buffers_larger_than(table,MAX_TDC_BLOB_SIZE);
+    
     table->file->ha_reset();
     table->in_use=0;
     if (unused_tables)
diff --git a/sql/table.cc b/sql/table.cc
index ebf3dfd748e..58cbde74822 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -1999,6 +1999,28 @@ void free_blobs(register TABLE *table)
 }
 
 
+/**
+  Reclaim temporary blob storage which is bigger than 
+  a threshold.
+ 
+  @param table A handle to the TABLE object containing blob fields
+  @param size The threshold value.
+ 
+*/
+
+void free_field_buffers_larger_than(TABLE *table, uint32 size)
+{
+  uint *ptr, *end;
+  for (ptr= table->s->blob_field, end=ptr + table->s->blob_fields ;
+       ptr != end ;
+       ptr++)
+  {
+    Field_blob *blob= (Field_blob*) table->field[*ptr];
+    if (blob->get_field_buffer_size() > size)
+        blob->free();
+  }
+}
+
 	/* Find where a form starts */
 	/* if formname is NullS then only formnames is read */
 
diff --git a/sql/table.h b/sql/table.h
index 75ddaf69c10..da0e089794f 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -935,6 +935,9 @@ typedef struct st_schema_table
 #define VIEW_CHECK_ERROR      1
 #define VIEW_CHECK_SKIP       2
 
+/** The threshold size a blob field buffer before it is freed */
+#define MAX_TDC_BLOB_SIZE 65536
+
 struct st_lex;
 class select_union;
 class TMP_TABLE_PARAM;
-- 
2.30.9