Commit 38b272ffbbdaae276d636aec4ef84af407d16181

suzuki toshiya 2011-01-09T22:49:07

[cache] Notice if a cache query induced the node list change. Some node comparators (comparing the cache node content and the properties specified by the query) can flush the cache node to prevent the cache inflation. The change may invalidate the pointers to the node obtained before the node comparison, so the change should be noticed to the caller. The problem caused by the cache node changing is reported by Harsha, see Savannah bug #31923. * src/cache/ftccache.h (FTC_Node_CompareFunc): Add new argument `FT_Bool* list_changed' to indicate the change of the cached nodes to the caller. (FTC_CACHE_LOOKUP_CMP): Watch the change of the cached nodes by `_list_changed'. (FTC_CACHE_TRYLOOP_END): Take new macro argument `_list_changed' and update it when FTC_Manager_FlushN() flushes any nodes. * src/cache/ftccback.h (ftc_snode_compare): Updated to fit with new FTC_Node_CompareFunc type. (ftc_gnode_compare): Ditto. * src/cache/ftcbasic.c: Include FT_INTERNAL_OBJECTS_H to use TRUE/FALSE macros. (ftc_basic_gnode_compare_faceid): New argument `FT_Bool* list_changed' to indicate the change of the cache nodes, anyway, it is always FALSE. * src/cache/ftccmap.c: Include FT_INTERNAL_OBJECTS_H to use TRUE/FALSE macros. (ftc_cmap_node_compare): New argument `FT_Bool* list_changed' to indicate the change of the cache nodes, anyway, it is always FALSE. (ftc_cmap_node_remove_faceid): Ditto. * src/cache/ftccache.c (FTC_Cache_NewNode): Pass a NULL pointer to FTC_CACHE_TRYLOOP_END(), because the result is not needed. (FTC_Cache_Lookup): Watch the change of the cache nodes by `list_changed'. (FTC_Cache_RemoveFaceID): Ditto. * src/cache/ftcglyph.c: Include FT_INTERNAL_OBJECTS_H to use TRUE/FALSE macros. (ftc_gnode_compare): New argument `FT_Bool* list_changed' to indicate the change of the cache nodes, anyway, it is always FALSE. (FTC_GNode_Compare): New argument `FT_Bool* list_changed' to be passed to ftc_gnode_compare(). * src/cache/ftcglyph.h (FTC_GNode_Compare): Ditto. * src/cache/ftcsbits.c (ftc_snode_compare): New argument `FT_Bool* list_changed' to indicate the change of the cache nodes, anyway. It is updated by FTC_CACHE_TRYLOOP(). (FTC_SNode_Compare): New argument `FT_Bool* list_changed' to be passed to ftc_snode_compare(). * src/cache/ftcsbits.h (FTC_SNode_Compare): Ditto.

diff --git a/ChangeLog b/ChangeLog
index 0d8506d..182476c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,59 @@
 2010-01-09  suzuki toshiya  <mpsuzuki@hiroshima-u.ac.jp>
 
+	[cache] Notice if a cache query induced the node list change.
+
+	Some node comparators (comparing the cache node content and 
+	the properties specified by the query) can flush the cache
+	node to prevent the cache inflation.  The change may
+	invalidate the pointers to the node obtained before the node
+	comparison, so the change should be noticed to the caller.
+	The problem caused by the cache node changing is reported by
+	Harsha, see Savannah bug #31923.
+
+	* src/cache/ftccache.h (FTC_Node_CompareFunc): Add new
+	argument `FT_Bool* list_changed' to indicate the change of
+	the cached nodes to the caller.
+	(FTC_CACHE_LOOKUP_CMP): Watch the change of the cached nodes
+	by `_list_changed'.
+	(FTC_CACHE_TRYLOOP_END): Take new macro argument `_list_changed'
+	and update it when FTC_Manager_FlushN() flushes any nodes.
+
+	* src/cache/ftccback.h (ftc_snode_compare): Updated to fit
+	with new FTC_Node_CompareFunc type.  (ftc_gnode_compare): Ditto.
+
+	* src/cache/ftcbasic.c: Include FT_INTERNAL_OBJECTS_H to
+	use TRUE/FALSE macros.  (ftc_basic_gnode_compare_faceid):
+	New argument `FT_Bool* list_changed' to indicate the change
+	of the cache nodes, anyway, it is always FALSE.
+
+	* src/cache/ftccmap.c: Include FT_INTERNAL_OBJECTS_H to
+	use TRUE/FALSE macros.  (ftc_cmap_node_compare):
+	New argument `FT_Bool* list_changed' to indicate the change
+	of the cache nodes, anyway, it is always FALSE.
+	(ftc_cmap_node_remove_faceid): Ditto.
+
+	* src/cache/ftccache.c (FTC_Cache_NewNode): Pass a NULL
+	pointer to FTC_CACHE_TRYLOOP_END(), because the result is
+	not needed.  (FTC_Cache_Lookup): Watch the change of the cache
+	nodes by `list_changed'.  (FTC_Cache_RemoveFaceID): Ditto.
+
+	* src/cache/ftcglyph.c: Include FT_INTERNAL_OBJECTS_H to
+	use TRUE/FALSE macros.  (ftc_gnode_compare): New argument
+	`FT_Bool* list_changed' to indicate the change of the cache
+	nodes, anyway, it is always FALSE.  (FTC_GNode_Compare):
+	New argument `FT_Bool* list_changed' to be passed to
+	ftc_gnode_compare().
+	* src/cache/ftcglyph.h (FTC_GNode_Compare): Ditto.
+
+	* src/cache/ftcsbits.c (ftc_snode_compare): New argument
+	`FT_Bool* list_changed' to indicate the change of the cache
+	nodes, anyway. It is updated by FTC_CACHE_TRYLOOP().
+	(FTC_SNode_Compare): New argument `FT_Bool* list_changed'
+	to be passed to ftc_snode_compare().
+	* src/cache/ftcsbits.h (FTC_SNode_Compare): Ditto.
+
+2010-01-09  suzuki toshiya  <mpsuzuki@hiroshima-u.ac.jp>
+
 	[cache] Fit FTC_GNode_Compare() to FTC_Node_CompareFunc.
 
 	* src/cache/ftcglyph.h (FTC_GNode_Compare): Add the 3rd
diff --git a/src/cache/ftcbasic.c b/src/cache/ftcbasic.c
index 609ff78..48cfab0 100644
--- a/src/cache/ftcbasic.c
+++ b/src/cache/ftcbasic.c
@@ -17,6 +17,7 @@
 
 
 #include <ft2build.h>
+#include FT_INTERNAL_OBJECTS_H
 #include FT_INTERNAL_DEBUG_H
 #include FT_CACHE_H
 #include "ftcglyph.h"
@@ -237,7 +238,8 @@
   FT_CALLBACK_DEF( FT_Bool )
   ftc_basic_gnode_compare_faceid( FTC_Node    ftcgnode,
                                   FT_Pointer  ftcface_id,
-                                  FTC_Cache   cache )
+                                  FTC_Cache   cache,
+                                  FT_Bool*    list_changed )
   {
     FTC_GNode        gnode   = (FTC_GNode)ftcgnode;
     FTC_FaceID       face_id = (FTC_FaceID)ftcface_id;
@@ -245,6 +247,8 @@
     FT_Bool          result;
 
 
+    if ( list_changed )
+      *list_changed = FALSE;
     result = FT_BOOL( family->attrs.scaler.face_id == face_id );
     if ( result )
     {
diff --git a/src/cache/ftccache.c b/src/cache/ftccache.c
index f28176e..9a52560 100644
--- a/src/cache/ftccache.c
+++ b/src/cache/ftccache.c
@@ -461,7 +461,7 @@
     {
       error = cache->clazz.node_new( &node, query, cache );
     }
-    FTC_CACHE_TRYLOOP_END();
+    FTC_CACHE_TRYLOOP_END( NULL );
 
     if ( error )
       node = NULL;
@@ -490,6 +490,7 @@
     FTC_Node*  pnode;
     FTC_Node   node;
     FT_Error   error = FTC_Err_Ok;
+    FT_Bool    list_changed = FALSE;
 
     FTC_Node_CompareFunc  compare = cache->clazz.node_compare;
 
@@ -504,7 +505,8 @@
       if ( node == NULL )
         goto NewNode;
 
-      if ( node->hash == hash && compare( node, query, cache ) )
+      if ( node->hash == hash                         &&
+           compare( node, query, cache, &list_changed ) )
         break;
 
       pnode = &node->link;
@@ -554,12 +556,13 @@
       for ( ;; )
       {
         FTC_Node  node = *pnode;
+        FT_Bool   list_changed = FALSE;
 
 
         if ( node == NULL )
           break;
 
-        if ( cache->clazz.node_remove_faceid( node, face_id, cache ) )
+        if ( cache->clazz.node_remove_faceid( node, face_id, cache, &list_changed ) )
         {
           *pnode     = node->link;
           node->link = frees;
diff --git a/src/cache/ftccache.h b/src/cache/ftccache.h
index 281ff39..b6b40a0 100644
--- a/src/cache/ftccache.h
+++ b/src/cache/ftccache.h
@@ -115,7 +115,8 @@ FT_BEGIN_HEADER
   typedef FT_Bool
   (*FTC_Node_CompareFunc)( FTC_Node    node,
                            FT_Pointer  key,
-                           FTC_Cache   cache );
+                           FTC_Cache   cache,
+                           FT_Bool*    list_changed );
 
 
   typedef void
@@ -218,6 +219,7 @@ FT_BEGIN_HEADER
     FTC_Cache             _cache   = FTC_CACHE(cache);                   \
     FT_PtrDist            _hash    = (FT_PtrDist)(hash);                 \
     FTC_Node_CompareFunc  _nodcomp = (FTC_Node_CompareFunc)(nodecmp);    \
+    FT_Bool               _list_changed = FALSE;                         \
                                                                          \
                                                                          \
     error = FTC_Err_Ok;                                                  \
@@ -230,7 +232,8 @@ FT_BEGIN_HEADER
       if ( _node == NULL )                                               \
         goto _NewNode;                                                   \
                                                                          \
-      if ( _node->hash == _hash && _nodcomp( _node, query, _cache ) )    \
+      if ( _node->hash == _hash                             &&           \
+           _nodcomp( _node, query, _cache, &_list_changed ) )            \
         break;                                                           \
                                                                          \
       _pnode = &_node->link;                                             \
@@ -299,11 +302,14 @@ FT_BEGIN_HEADER
       FT_UInt  _try_done;
 
 
-#define FTC_CACHE_TRYLOOP_END()                                   \
+#define FTC_CACHE_TRYLOOP_END( list_changed )                     \
       if ( !error || error != FTC_Err_Out_Of_Memory )             \
         break;                                                    \
                                                                   \
       _try_done = FTC_Manager_FlushN( _try_manager, _try_count ); \
+      if ( _try_done > 0 && ( list_changed ) )                    \
+        *(FT_Bool*)( list_changed ) = TRUE;                       \
+                                                                  \
       if ( _try_done == 0 )                                       \
         break;                                                    \
                                                                   \
diff --git a/src/cache/ftccback.h b/src/cache/ftccback.h
index 4d0818d..4f5a326 100644
--- a/src/cache/ftccback.h
+++ b/src/cache/ftccback.h
@@ -57,13 +57,15 @@
   FT_LOCAL( FT_Bool )
   ftc_snode_compare( FTC_Node    snode,
                      FT_Pointer  gquery,
-                     FTC_Cache   cache );
+                     FTC_Cache   cache,
+                     FT_Bool*    list_changed );
 
 
   FT_LOCAL( FT_Bool )
   ftc_gnode_compare( FTC_Node    gnode,
                      FT_Pointer  gquery,
-                     FTC_Cache   cache );
+                     FTC_Cache   cache,
+                     FT_Bool*    list_changed );
 
 
   FT_LOCAL( FT_Error )
diff --git a/src/cache/ftccmap.c b/src/cache/ftccmap.c
index 15060ba..b0e85d1 100644
--- a/src/cache/ftccmap.c
+++ b/src/cache/ftccmap.c
@@ -22,6 +22,7 @@
 #include FT_CACHE_H
 #include "ftcmanag.h"
 #include FT_INTERNAL_MEMORY_H
+#include FT_INTERNAL_OBJECTS_H
 #include FT_INTERNAL_DEBUG_H
 
 #include "ftccback.h"
@@ -190,13 +191,16 @@
   FT_CALLBACK_DEF( FT_Bool )
   ftc_cmap_node_compare( FTC_Node    ftcnode,
                          FT_Pointer  ftcquery,
-                         FTC_Cache   cache )
+                         FTC_Cache   cache,
+                         FT_Bool*    list_changed )
   {
     FTC_CMapNode   node  = (FTC_CMapNode)ftcnode;
     FTC_CMapQuery  query = (FTC_CMapQuery)ftcquery;
     FT_UNUSED( cache );
 
 
+    if ( list_changed )
+      *list_changed = FALSE;
     if ( node->face_id    == query->face_id    &&
          node->cmap_index == query->cmap_index )
     {
@@ -213,12 +217,15 @@
   FT_CALLBACK_DEF( FT_Bool )
   ftc_cmap_node_remove_faceid( FTC_Node    ftcnode,
                                FT_Pointer  ftcface_id,
-                               FTC_Cache   cache )
+                               FTC_Cache   cache,
+                               FT_Bool*    list_changed )
   {
     FTC_CMapNode  node    = (FTC_CMapNode)ftcnode;
     FTC_FaceID    face_id = (FTC_FaceID)ftcface_id;
     FT_UNUSED( cache );
 
+    if ( list_changed )
+      *list_changed = FALSE;
     return FT_BOOL( node->face_id == face_id );
   }
 
diff --git a/src/cache/ftcglyph.c b/src/cache/ftcglyph.c
index 52a7933..ff041e8 100644
--- a/src/cache/ftcglyph.c
+++ b/src/cache/ftcglyph.c
@@ -17,6 +17,7 @@
 
 
 #include <ft2build.h>
+#include FT_INTERNAL_OBJECTS_H
 #include FT_CACHE_H
 #include "ftcglyph.h"
 #include FT_ERRORS_H
@@ -64,13 +65,16 @@
   FT_LOCAL_DEF( FT_Bool )
   ftc_gnode_compare( FTC_Node    ftcgnode,
                      FT_Pointer  ftcgquery,
-                     FTC_Cache   cache )
+                     FTC_Cache   cache,
+                     FT_Bool*    list_changed )
   {
     FTC_GNode   gnode  = (FTC_GNode)ftcgnode;
     FTC_GQuery  gquery = (FTC_GQuery)ftcgquery;
     FT_UNUSED( cache );
 
 
+    if ( list_changed )
+      *list_changed = FALSE;
     return FT_BOOL( gnode->family == gquery->family &&
                     gnode->gindex == gquery->gindex );
   }
@@ -81,9 +85,10 @@
   FT_LOCAL_DEF( FT_Bool )
   FTC_GNode_Compare( FTC_GNode   gnode,
                      FTC_GQuery  gquery,
-                     FTC_Cache   cache )
+                     FTC_Cache   cache,
+                     FT_Bool*    list_changed )
   {
-    return ftc_gnode_compare( FTC_NODE( gnode ), gquery, cache );
+    return ftc_gnode_compare( FTC_NODE( gnode ), gquery, cache, list_changed );
   }
 
 #endif
diff --git a/src/cache/ftcglyph.h b/src/cache/ftcglyph.h
index 3656743..d15ca3c 100644
--- a/src/cache/ftcglyph.h
+++ b/src/cache/ftcglyph.h
@@ -188,7 +188,8 @@ FT_BEGIN_HEADER
   FT_LOCAL( FT_Bool )
   FTC_GNode_Compare( FTC_GNode   gnode,
                      FTC_GQuery  gquery,
-                     FTC_Cache   cache );
+                     FTC_Cache   cache,
+                     FT_Bool*    list_changed );
 
 #endif
 
diff --git a/src/cache/ftcsbits.c b/src/cache/ftcsbits.c
index 52972a6..d4db994 100644
--- a/src/cache/ftcsbits.c
+++ b/src/cache/ftcsbits.c
@@ -324,7 +324,8 @@
   FT_LOCAL_DEF( FT_Bool )
   ftc_snode_compare( FTC_Node    ftcsnode,
                      FT_Pointer  ftcgquery,
-                     FTC_Cache   cache )
+                     FTC_Cache   cache,
+                     FT_Bool*    list_changed )
   {
     FTC_SNode   snode  = (FTC_SNode)ftcsnode;
     FTC_GQuery  gquery = (FTC_GQuery)ftcgquery;
@@ -333,6 +334,8 @@
     FT_Bool     result;
 
 
+    if (list_changed)
+      *list_changed = FALSE;
     result = FT_BOOL( gnode->family == gquery->family                    &&
                       (FT_UInt)( gindex - gnode->gindex ) < snode->count );
     if ( result )
@@ -386,7 +389,7 @@
         {
           error = ftc_snode_load( snode, cache->manager, gindex, &size );
         }
-        FTC_CACHE_TRYLOOP_END();
+        FTC_CACHE_TRYLOOP_END( list_changed );
 
         ftcsnode->ref_count--;  /* unlock the node */
 
@@ -406,9 +409,10 @@
   FT_LOCAL_DEF( FT_Bool )
   FTC_SNode_Compare( FTC_SNode   snode,
                      FTC_GQuery  gquery,
-                     FTC_Cache   cache )
+                     FTC_Cache   cache,
+                     FT_Bool*    list_changed )
   {
-    return ftc_snode_compare( FTC_NODE( snode ), gquery, cache );
+    return ftc_snode_compare( FTC_NODE( snode ), gquery, cache, list_changed );
   }
 
 #endif
diff --git a/src/cache/ftcsbits.h b/src/cache/ftcsbits.h
index 336aa9b..5548149 100644
--- a/src/cache/ftcsbits.h
+++ b/src/cache/ftcsbits.h
@@ -88,7 +88,8 @@ FT_BEGIN_HEADER
   FT_LOCAL( FT_Bool )
   FTC_SNode_Compare( FTC_SNode   snode,
                      FTC_GQuery  gquery,
-                     FTC_Cache   cache );
+                     FTC_Cache   cache,
+                     FT_Bool*    list_changed);
 
 #endif