operation cache working

but see notes in file
This commit is contained in:
John Cupitt 2011-09-10 14:38:39 +01:00
parent 5d1accfc83
commit f9b8e0d88f
2 changed files with 85 additions and 40 deletions

View File

@ -31,16 +31,19 @@
TODO
vips_object_build() needs a new type ... should return the
VipsObject it makes
should the cache be thread-private? or lock? or say operations can
only be made from the main thread?
only cache operation_new()? (this is what we do now)
listen for invalidate
keep operations alive? at the moment
vips_min( im, &d, NULL );
will never get cached since it produces no persistent output ... we'd
need to keep a ref to the operation in the cache and only drop after a
few seconds or if we have more than 10,000 cached operations
*/
/*
@ -74,10 +77,14 @@
static GHashTable *vips_object_cache = NULL;
/* generic is the general type of the value. For example, the value could be
* held in a GParamSpec allowing OBJECT, but the value could be of type
* VipsImage. generics are much faster to compare.
*/
static unsigned int
vips_value_hash( GValue *value )
vips_value_hash( GType generic, GValue *value )
{
switch( G_VALUE_TYPE( value ) ) {
switch( generic ) {
case G_TYPE_BOOLEAN:
return( (unsigned int) g_value_get_boolean( value ) );
case G_TYPE_CHAR:
@ -144,25 +151,44 @@ vips_value_hash( GValue *value )
default:
{
/* Fallback: convert to a string and hash that. This is very
* slow, print a warning if we use it so we can add another
* case.
/* These GTypes are not compile-time constants and need to be
* in ifs.
*/
char *s;
unsigned int hash;
if( generic == VIPS_TYPE_IMAGE )
return( g_direct_hash( g_value_get_object( value ) ) );
else {
/* Fallback: convert to a string and hash that.
* This is very slow, print a warning if we use it
* so we can add another case.
*/
char *s;
unsigned int hash;
s = g_strdup_value_contents( value );
hash = g_str_hash( s );
printf( "vips_value_hash: no case for %s\n", s );
g_free( s );
s = g_strdup_value_contents( value );
hash = g_str_hash( s );
return( hash );
printf( "vips_value_hash: no case for %s\n", s );
printf( "\ttype %d, %s\n",
(int) G_VALUE_TYPE( value ),
g_type_name( G_VALUE_TYPE( value ) ) );
printf( "\tgeneric %d, %s\n",
(int) G_VALUE_TYPE( generic ),
g_type_name( generic ) );
g_free( s );
return( hash );
}
}
}
}
/* generic is the general type of the value. For example, the value could be
* held in a GParamSpec allowing OBJECT, but the value could be of type
* VipsImage. generics are much faster to compare.
*/
static gboolean
vips_value_equal( GValue *v1, GValue *v2 )
vips_value_equal( GType generic, GValue *v1, GValue *v2 )
{
GType t1 = G_VALUE_TYPE( v1 );
GType t2 = G_VALUE_TYPE( v2 );
@ -225,21 +251,38 @@ vips_value_equal( GValue *v1, GValue *v2 )
default:
{
/* Fallback: convert to a string and hash that. This is very
* slow, print a warning if we use it so we can add another
* case.
/* These GTypes are not compile-time constants and need to be
* in ifs.
*/
char *s1;
char *s2;
gboolean equal;
if( generic == VIPS_TYPE_IMAGE )
return( g_value_get_object( v1 ) ==
g_value_get_object( v2 ) );
else {
/* Fallback: convert to a string and compare that.
* This is very slow, print a warning if we use it
* so we can add another case.
*/
char *s1;
char *s2;
gboolean equal;
s1 = g_strdup_value_contents( v1 );
s2 = g_strdup_value_contents( v2 );
equal = strcmp( s1, s2 ) == 0;
g_free( s1 );
g_free( s2 );
s1 = g_strdup_value_contents( v1 );
s2 = g_strdup_value_contents( v2 );
equal = strcmp( s1, s2 ) == 0;
return( equal );
printf( "vips_value_equal: no case for %s, %s\n",
s1, s2 );
printf( "\tt1 %d, %s\n", (int) t1, g_type_name( t1 ) );
printf( "\tt2 %d, %s\n", (int) t2, g_type_name( t2 ) );
printf( "\tgeneric %d, %s\n",
(int) G_VALUE_TYPE( generic ),
g_type_name( generic ) );
g_free( s1 );
g_free( s2 );
return( equal );
}
}
}
}
@ -262,7 +305,7 @@ vips_object_hash_arg( VipsObject *object,
g_value_init( &value, type );
g_object_get_property( G_OBJECT( object ),
g_param_spec_get_name( pspec ), &value );
*hash = (*hash << 1) ^ vips_value_hash( &value );
*hash = (*hash << 1) ^ vips_value_hash( type, &value );
g_value_unset( &value );
}
@ -318,7 +361,7 @@ vips_object_equal_arg( VipsObject *object,
g_value_init( &v2, type );
g_object_get_property( G_OBJECT( object ), name, &v1 );
g_object_get_property( G_OBJECT( other ), name, &v2 );
equal = vips_value_equal( &v1, &v2 );
equal = vips_value_equal( type, &v1, &v2 );
g_value_unset( &v1 );
g_value_unset( &v2 );

View File

@ -469,8 +469,10 @@ vips_operation_get_valist_optional( VipsOperation *operation, va_list ap )
return( 0 );
}
/* This can change operation to point at an old, cached one.
*/
static int
vips_call_required_optional( VipsOperation *operation,
vips_call_required_optional( VipsOperation **operation,
va_list required, va_list optional )
{
int result;
@ -483,22 +485,22 @@ vips_call_required_optional( VipsOperation *operation,
*/
va_copy( a, required );
va_copy( b, optional );
result = vips_operation_set_valist_required( operation, a ) ||
vips_operation_set_valist_optional( operation, b );
result = vips_operation_set_valist_required( *operation, a ) ||
vips_operation_set_valist_optional( *operation, b );
va_end( a );
va_end( b );
/* Build from cache.
*/
if( vips_object_build_cache( (VipsObject **) &operation ) )
if( vips_object_build_cache( (VipsObject **) operation ) )
return( -1 );
/* Walk args again, writing output.
*/
va_copy( a, required );
va_copy( b, optional );
result = vips_operation_get_valist_required( operation, required ) ||
vips_operation_get_valist_optional( operation, optional );
result = vips_operation_get_valist_required( *operation, required ) ||
vips_operation_get_valist_optional( *operation, optional );
va_end( a );
va_end( b );
@ -548,7 +550,7 @@ vips_call( const char *operation_name, ... )
}
} VIPS_ARGUMENT_FOR_ALL_END
result = vips_call_required_optional( operation, required, optional );
result = vips_call_required_optional( &operation, required, optional );
va_end( required );
va_end( optional );
@ -589,7 +591,7 @@ vips_call_split( const char *operation_name, va_list optional, ... )
#endif /*VIPS_DEBUG*/
va_start( required, optional );
result = vips_call_required_optional( operation, required, optional );
result = vips_call_required_optional( &operation, required, optional );
va_end( required );
/* Build failed: junk args and back out.