1 /* cache vips operations
2  *
3  * 20/6/12
4  * 	- try to make it compile on centos5
5  * 7/7/12
6  * 	- add a lock so we can run operations from many threads
7  * 28/11/19 [MaxKellermann]
8  * 	- make invalidate advisory rather than immediate
9  */
10 
11 /*
12 
13     This file is part of VIPS.
14 
15     VIPS is free software; you can redistribute it and/or modify
16     it under the terms of the GNU Lesser General Public License as published by
17     the Free Software Foundation; either version 2 of the License, or
18     (at your option) any later version.
19 
20     This program is distributed in the hope that it will be useful,
21     but WITHOUT ANY WARRANTY; without even the implied warranty of
22     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23     GNU Lesser General Public License for more details.
24 
25     You should have received a copy of the GNU Lesser General Public License
26     along with this program; if not, write to the Free Software
27     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
28     02110-1301  USA
29 
30  */
31 
32 /*
33 
34     These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
35 
36  */
37 
38 /*
39 
40    TODO
41 
42 	what about delayed writes ... do we ever write in close? we shouldn't,
43 	should do in evalend or written or somesuch
44 
45 	use g_param_values_cmp() instead of value_equal()?
46 
47  */
48 
49 /*
50 #define VIPS_DEBUG
51 #define DEBUG
52  */
53 
54 #ifdef HAVE_CONFIG_H
55 #include <config.h>
56 #endif /*HAVE_CONFIG_H*/
57 #include <vips/intl.h>
58 
59 #include <stdio.h>
60 #include <stdlib.h>
61 #include <string.h>
62 #ifdef HAVE_UNISTD_H
63 #include <unistd.h>
64 #endif /*HAVE_UNISTD_H*/
65 #include <ctype.h>
66 
67 #include <vips/vips.h>
68 #include <vips/internal.h>
69 #include <vips/debug.h>
70 
71 /* Set by GOption from the command line, eg. "12m".
72  */
73 gboolean vips__cache_dump = FALSE;
74 gboolean vips__cache_trace = FALSE;
75 
76 /* Max number of cached operations.
77  *
78  * It was 10,000, but this was too high for batch-style applications with
79  * little reuse.
80  */
81 static int vips_cache_max = 100;
82 
83 /* How many tracked open files we allow before we start dropping cache.
84  */
85 static int vips_cache_max_files = 100;
86 
87 /* How much RAM we spend on caches before we start dropping cached operations
88  * ... default 100mb.
89  *
90  * It was 1gb, but that's a lot of memory for things like vipsthumbnail where
91  * there will be (almost) no reuse. Default low and let apps raise it if it'd
92  * be useful.
93  */
94 static size_t vips_cache_max_mem = 100 * 1024 * 1024;
95 
96 /* Hold a ref to all "recent" operations.
97  */
98 static GHashTable *vips_cache_table = NULL;
99 
100 /* A 'time' counter: increment on all cache ops. Use this to detect LRU.
101  */
102 static int vips_cache_time = 0;
103 
104 /* Protect cache access with this.
105  */
106 static GMutex *vips_cache_lock = NULL;
107 
108 /* Old versions of glib are missing these. When we abandon centos 5, switch to
109  * g_int64_hash() and g_double_hash().
110  */
111 #define INT64_HASH(X) (g_direct_hash(X))
112 #define DOUBLE_HASH(X) (g_direct_hash(X))
113 
114 /* A cache entry.
115  */
116 typedef struct _VipsOperationCacheEntry {
117 	VipsOperation *operation;
118 
119 	/* When we added this operation to cache .. used to find LRU for
120 	 * flush.
121 	 */
122 	int time;
123 
124 	/* We listen for "invalidate" from the operation. Track the id here so
125 	 * we can disconnect when we drop an operation.
126 	 */
127 	gulong invalidate_id;
128 
129 	/* Set if someone thinks this cache entry should be dropped.
130 	 */
131 	gboolean invalid;
132 
133 } VipsOperationCacheEntry;
134 
135 /* Pass in the pspec so we can get the generic type. For example, a
136  * held in a GParamSpec allowing OBJECT, but the value could be of type
137  * VipsImage. generics are much faster to compare.
138  */
139 static unsigned int
vips_value_hash(GParamSpec * pspec,GValue * value)140 vips_value_hash( GParamSpec *pspec, GValue *value )
141 {
142 	GType generic = G_PARAM_SPEC_TYPE( pspec );
143 
144 	/* Not compile-time constants, so we have to use a set of if()s. Could
145 	 * make a table at run time I guess.
146 	 */
147 
148 	if( generic == G_TYPE_PARAM_BOOLEAN )
149 		return( (unsigned int) g_value_get_boolean( value ) );
150 	else if( generic == G_TYPE_PARAM_CHAR )
151 		return( (unsigned int) g_value_get_schar( value ) );
152 	else if( generic == G_TYPE_PARAM_UCHAR )
153 		return( (unsigned int) g_value_get_uchar( value ) );
154 	else if( generic == G_TYPE_PARAM_INT )
155 		return( (unsigned int) g_value_get_int( value ) );
156 	else if( generic == G_TYPE_PARAM_UINT )
157 		return( (unsigned int) g_value_get_uint( value ) );
158 	else if( generic == G_TYPE_PARAM_LONG )
159 		return( (unsigned int) g_value_get_long( value ) );
160 	else if( generic == G_TYPE_PARAM_ULONG )
161 		return( (unsigned int) g_value_get_ulong( value ) );
162 	else if( generic == G_TYPE_PARAM_ENUM )
163 		return( (unsigned int) g_value_get_enum( value ) );
164 	else if( generic == G_TYPE_PARAM_FLAGS )
165 		return( (unsigned int) g_value_get_flags( value ) );
166 	else if( generic == G_TYPE_PARAM_UINT64 ) {
167 		guint64 i = g_value_get_uint64( value );
168 
169 		return( INT64_HASH( (gint64 *) &i ) );
170 	}
171 	else if( generic == G_TYPE_PARAM_INT64 ) {
172 		gint64 i = g_value_get_int64( value );
173 
174 		return( INT64_HASH( &i ) );
175 	}
176 	else if( generic == G_TYPE_PARAM_FLOAT ) {
177 		float f = g_value_get_float( value );
178 
179 		return( g_direct_hash( (void *) &f ) );
180 	}
181 	else if( generic == G_TYPE_PARAM_DOUBLE ) {
182 		double d = g_value_get_double( value );
183 
184 		return( DOUBLE_HASH( &d ) );
185 	}
186 	else if( generic == G_TYPE_PARAM_STRING ) {
187 		const char *s = g_value_get_string( value );
188 
189 		return( s ? g_str_hash( s ) : 0 );
190 	}
191 	else if( generic == G_TYPE_PARAM_BOXED ) {
192 		void *p = g_value_get_boxed( value );
193 
194 		return( p ? g_direct_hash( p ) : 0 );
195 	}
196 	else if( generic == G_TYPE_PARAM_POINTER ) {
197 		void *p = g_value_get_pointer( value );
198 
199 		return( p ? g_direct_hash( p ) : 0 );
200 	}
201 	else if( generic == G_TYPE_PARAM_OBJECT ) {
202 		void *p = g_value_get_object( value );
203 
204 		return( p ? g_direct_hash( p ) : 0 );
205 	}
206 	else {
207 		/* Fallback: convert to a string and hash that.
208 		 * This is very slow, print a warning if we use it
209 		 * so we can add another case.
210 		 */
211 		char *s;
212 		unsigned int hash;
213 
214 		s = g_strdup_value_contents( value );
215 		hash = g_str_hash( s );
216 
217 		printf( "vips_value_hash: no case for %s\n", s );
218 		printf( "\ttype %d, %s\n",
219 			(int) G_VALUE_TYPE( value ),
220 			g_type_name( G_VALUE_TYPE( value ) ) );
221 		printf( "\tgeneric %d, %s\n",
222 			(int) G_VALUE_TYPE( generic ),
223 			g_type_name( generic ) );
224 
225 		g_free( s );
226 
227 		return( hash );
228 	}
229 }
230 
231 /* Pass in the pspec so we can get the generic type. For example, a
232  * value could be held in a GParamSpec allowing OBJECT, but the value
233  * could be of type VipsImage. generics are much faster to compare.
234  */
235 static gboolean
vips_value_equal(GParamSpec * pspec,GValue * v1,GValue * v2)236 vips_value_equal( GParamSpec *pspec, GValue *v1, GValue *v2 )
237 {
238 	GType generic = G_PARAM_SPEC_TYPE( pspec );
239 	GType t1 = G_VALUE_TYPE( v1 );
240 	GType t2 = G_VALUE_TYPE( v2 );
241 
242 	if( t1 != t2 )
243 		return( FALSE );
244 
245 	/* Not compile-time constants, so we have to use a set of if()s. Could
246 	 * make a table at run time I guess.
247 	 */
248 
249 	if( generic == G_TYPE_PARAM_BOOLEAN )
250 		return( g_value_get_boolean( v1 ) ==
251 			g_value_get_boolean( v2 ) );
252 	else if( generic == G_TYPE_PARAM_CHAR )
253 		return( g_value_get_schar( v1 ) ==
254 			g_value_get_schar( v2 ) );
255 	if( generic == G_TYPE_PARAM_UCHAR )
256 		return( g_value_get_uchar( v1 ) ==
257 			g_value_get_uchar( v2 ) );
258 	if( generic == G_TYPE_PARAM_INT )
259 		return( g_value_get_int( v1 ) ==
260 			g_value_get_int( v2 ) );
261 	if( generic == G_TYPE_PARAM_UINT )
262 		return( g_value_get_uint( v1 ) ==
263 			g_value_get_uint( v2 ) );
264 	if( generic == G_TYPE_PARAM_LONG )
265 		return( g_value_get_long( v1 ) ==
266 			g_value_get_long( v2 ) );
267 	if( generic == G_TYPE_PARAM_ULONG )
268 		return( g_value_get_ulong( v1 ) ==
269 			g_value_get_ulong( v2 ) );
270 	if( generic == G_TYPE_PARAM_ENUM )
271 		return( g_value_get_enum( v1 ) ==
272 			g_value_get_enum( v2 ) );
273 	if( generic == G_TYPE_PARAM_FLAGS )
274 		return( g_value_get_flags( v1 ) ==
275 			g_value_get_flags( v2 ) );
276 	if( generic == G_TYPE_PARAM_UINT64 )
277 		return( g_value_get_uint64( v1 ) ==
278 			g_value_get_uint64( v2 ) );
279 	if( generic == G_TYPE_PARAM_INT64 )
280 		return( g_value_get_int64( v1 ) ==
281 			g_value_get_int64( v2 ) );
282 	if( generic == G_TYPE_PARAM_FLOAT )
283 		return( g_value_get_float( v1 ) ==
284 			g_value_get_float( v2 ) );
285 	if( generic == G_TYPE_PARAM_DOUBLE )
286 		return( g_value_get_double( v1 ) ==
287 			g_value_get_double( v2 ) );
288 	if( generic == G_TYPE_PARAM_STRING ) {
289 		const char *s1 = g_value_get_string( v1 );
290 		const char *s2 = g_value_get_string( v2 );
291 
292 		if( s1 == s2 )
293 			return( TRUE );
294 		else
295 			return( s1 && s2 && strcmp( s1, s2 ) == 0 );
296 	}
297 	if( generic == G_TYPE_PARAM_BOXED )
298 		return( g_value_get_boxed( v1 ) ==
299 			g_value_get_boxed( v2 ) );
300 	if( generic == G_TYPE_PARAM_POINTER )
301 		return( g_value_get_pointer( v1 ) ==
302 			g_value_get_pointer( v2 ) );
303 	if( generic == G_TYPE_PARAM_OBJECT )
304 		return( g_value_get_object( v1 ) ==
305 			g_value_get_object( v2 ) );
306 	else {
307 		/* Fallback: convert to a string and compare that.
308 		 * This is very slow, print a warning if we use it
309 		 * so we can add another case.
310 		 */
311 		char *s1;
312 		char *s2;
313 		gboolean equal;
314 
315 		s1 = g_strdup_value_contents( v1 );
316 		s2 = g_strdup_value_contents( v2 );
317 		equal = strcmp( s1, s2 ) == 0;
318 
319 		printf( "vips_value_equal: no case for %s, %s\n",
320 			s1, s2 );
321 		printf( "\tt1 %d, %s\n", (int) t1, g_type_name( t1 ) );
322 		printf( "\tt2 %d, %s\n", (int) t2, g_type_name( t2 ) );
323 		printf( "\tgeneric %d, %s\n",
324 			(int) G_VALUE_TYPE( generic ),
325 			g_type_name( generic ) );
326 
327 		g_free( s1 );
328 		g_free( s2 );
329 
330 		return( equal );
331 	}
332 }
333 
334 static void *
vips_object_hash_arg(VipsObject * object,GParamSpec * pspec,VipsArgumentClass * argument_class,VipsArgumentInstance * argument_instance,void * a,void * b)335 vips_object_hash_arg( VipsObject *object,
336 	GParamSpec *pspec,
337 	VipsArgumentClass *argument_class,
338 	VipsArgumentInstance *argument_instance,
339 	void *a, void *b )
340 {
341 	unsigned int *hash = (unsigned int *) a;
342 
343 	if( (argument_class->flags & VIPS_ARGUMENT_CONSTRUCT) &&
344 		(argument_class->flags & VIPS_ARGUMENT_INPUT) &&
345 		argument_instance->assigned ) {
346 		const char *name = g_param_spec_get_name( pspec );
347 		GType type = G_PARAM_SPEC_VALUE_TYPE( pspec );
348 		GValue value = { 0, };
349 
350 		g_value_init( &value, type );
351 		g_object_get_property( G_OBJECT( object ), name, &value );
352 		*hash = (*hash << 1) ^ vips_value_hash( pspec, &value );
353 		g_value_unset( &value );
354 	}
355 
356 	return( NULL );
357 }
358 
359 /* Find a hash from the input arguments to a VipsOperstion.
360  */
361 static unsigned int
vips_operation_hash(VipsOperation * operation)362 vips_operation_hash( VipsOperation *operation )
363 {
364 	if( !operation->found_hash ) {
365 		guint hash;
366 
367 		/* Include the operation type in the hash.
368 		 */
369 		hash = (guint) G_OBJECT_TYPE( operation );
370 		(void) vips_argument_map( VIPS_OBJECT( operation ),
371 			vips_object_hash_arg, &hash, NULL );
372 
373 		/* Make sure we can't have a zero hash value.
374 		 */
375 		hash |= 1;
376 
377 		operation->hash = hash;
378 		operation->found_hash = TRUE;
379 	}
380 
381 	return( operation->hash );
382 }
383 
384 static void *
vips_object_equal_arg(VipsObject * object,GParamSpec * pspec,VipsArgumentClass * argument_class,VipsArgumentInstance * argument_instance,void * a,void * b)385 vips_object_equal_arg( VipsObject *object,
386 	GParamSpec *pspec,
387 	VipsArgumentClass *argument_class,
388 	VipsArgumentInstance *argument_instance,
389 	void *a, void *b )
390 {
391 	VipsObject *other = (VipsObject *) a;
392 
393 	const char *name = g_param_spec_get_name( pspec );
394 	GType type = G_PARAM_SPEC_VALUE_TYPE( pspec );
395 	GValue v1 = { 0, };
396 	GValue v2 = { 0, };
397 
398 	gboolean equal;
399 
400 	/* Only test assigned input constructor args.
401 	 */
402 	if( !(argument_class->flags & VIPS_ARGUMENT_CONSTRUCT) ||
403 		!(argument_class->flags & VIPS_ARGUMENT_INPUT) ||
404 		!argument_instance->assigned )
405 		return( NULL );
406 
407 	/* If this is an optional arg, we need to check that this was
408 	 * assigned on @other as well.
409 	 */
410 	if( !(argument_class->flags & VIPS_ARGUMENT_REQUIRED) &&
411 		!vips_object_argument_isset( other, name ) )
412 		/* Optional and was not set on other ... we've found a
413 		 * difference!
414 		 */
415 		return( object );
416 
417 	g_value_init( &v1, type );
418 	g_value_init( &v2, type );
419 	g_object_get_property( G_OBJECT( object ), name, &v1 );
420 	g_object_get_property( G_OBJECT( other ), name, &v2 );
421 	equal = vips_value_equal( pspec, &v1, &v2 );
422 	g_value_unset( &v1 );
423 	g_value_unset( &v2 );
424 
425 	/* Stop (return non-NULL) if we've found a difference.
426 	 */
427 	return( !equal ? object : NULL );
428 }
429 
430 /* Are two objects equal, ie. have the same inputs.
431  */
432 static gboolean
vips_operation_equal(VipsOperation * a,VipsOperation * b)433 vips_operation_equal( VipsOperation *a, VipsOperation *b )
434 {
435 	if( a == b )
436 		return( TRUE );
437 
438 	if( G_OBJECT_TYPE( a ) == G_OBJECT_TYPE( b ) &&
439 		vips_operation_hash( a ) == vips_operation_hash( b ) &&
440 		!vips_argument_map( VIPS_OBJECT( a ),
441 			vips_object_equal_arg, b, NULL ) )
442 		return( TRUE );
443 
444 	return( FALSE );
445 }
446 
447 void *
vips__cache_once_init(void * data)448 vips__cache_once_init( void *data )
449 {
450 	vips_cache_lock = vips_g_mutex_new();
451 
452 	vips_cache_table = g_hash_table_new(
453 		(GHashFunc) vips_operation_hash,
454 		(GEqualFunc) vips_operation_equal );
455 
456 	return( NULL );
457 }
458 
459 void
vips__cache_init(void)460 vips__cache_init( void )
461 {
462 	static GOnce once = G_ONCE_INIT;
463 
464 	VIPS_ONCE( &once, vips__cache_once_init, NULL );
465 }
466 
467 static void *
vips_cache_print_fn(void * value,void * a,void * b)468 vips_cache_print_fn( void *value, void *a, void *b )
469 {
470 	VipsOperationCacheEntry *entry = value;
471 
472 	char str[32768];
473 	VipsBuf buf = VIPS_BUF_STATIC( str );
474 
475 	vips_object_to_string( VIPS_OBJECT( entry->operation ), &buf );
476 
477 	printf( "%p - %s\n", value, vips_buf_all( &buf ) );
478 
479 	return( NULL );
480 }
481 
482 static void
vips_cache_print_nolock(void)483 vips_cache_print_nolock( void )
484 {
485 	if( vips_cache_table ) {
486 		printf( "Operation cache:\n" );
487 		vips_hash_table_map( vips_cache_table,
488 			vips_cache_print_fn, NULL, NULL );
489 	}
490 }
491 
492 /**
493  * vips_cache_print:
494  *
495  * Print the whole operation cache to stdout. Handy for debugging.
496  */
497 void
vips_cache_print(void)498 vips_cache_print( void )
499 {
500 	g_mutex_lock( vips_cache_lock );
501 
502 	vips_cache_print_nolock();
503 
504 	g_mutex_unlock( vips_cache_lock );
505 }
506 
507 static void *
vips_object_unref_arg(VipsObject * object,GParamSpec * pspec,VipsArgumentClass * argument_class,VipsArgumentInstance * argument_instance,void * a,void * b)508 vips_object_unref_arg( VipsObject *object,
509 	GParamSpec *pspec,
510 	VipsArgumentClass *argument_class,
511 	VipsArgumentInstance *argument_instance,
512 	void *a, void *b )
513 {
514 	if( (argument_class->flags & VIPS_ARGUMENT_CONSTRUCT) &&
515 		(argument_class->flags & VIPS_ARGUMENT_OUTPUT) &&
516 		argument_instance->assigned &&
517 		G_IS_PARAM_SPEC_OBJECT( pspec ) ) {
518 		GObject *value;
519 
520 		/* This will up the ref count for us.
521 		 */
522 		g_object_get( G_OBJECT( object ),
523 			g_param_spec_get_name( pspec ), &value, NULL );
524 
525 		/* Drop the ref we just got, then drop the ref we make when we
526 		 * added to the cache.
527 		 */
528 		g_object_unref( value );
529 		g_object_unref( value );
530 	}
531 
532 	return( NULL );
533 }
534 
535 static void
vips_cache_unref(VipsOperation * operation)536 vips_cache_unref( VipsOperation *operation )
537 {
538 #ifdef DEBUG
539 	printf( "vips_cache_unref: " );
540 	vips_object_print_summary( VIPS_OBJECT( operation ) );
541 #endif /*DEBUG*/
542 
543 	(void) vips_argument_map( VIPS_OBJECT( operation ),
544 		vips_object_unref_arg, NULL, NULL );
545 	g_object_unref( operation );
546 }
547 
548 /* Remove an operation from the cache.
549  */
550 static void
vips_cache_remove(VipsOperation * operation)551 vips_cache_remove( VipsOperation *operation )
552 {
553 	VipsOperationCacheEntry *entry = (VipsOperationCacheEntry *)
554 		g_hash_table_lookup( vips_cache_table, operation );
555 
556 #ifdef DEBUG
557 	printf( "vips_cache_remove: " );
558 	vips_object_print_summary( VIPS_OBJECT( operation ) );
559 #endif /*DEBUG*/
560 
561 	g_assert( entry );
562 
563 	if( entry->invalidate_id ) {
564 		g_signal_handler_disconnect( operation, entry->invalidate_id );
565 		entry->invalidate_id = 0;
566 	}
567 
568 	g_hash_table_remove( vips_cache_table, operation );
569 	vips_cache_unref( operation );
570 
571 	g_free( entry );
572 }
573 
574 static void *
vips_object_ref_arg(VipsObject * object,GParamSpec * pspec,VipsArgumentClass * argument_class,VipsArgumentInstance * argument_instance,void * a,void * b)575 vips_object_ref_arg( VipsObject *object,
576 	GParamSpec *pspec,
577 	VipsArgumentClass *argument_class,
578 	VipsArgumentInstance *argument_instance,
579 	void *a, void *b )
580 {
581 	if( (argument_class->flags & VIPS_ARGUMENT_CONSTRUCT) &&
582 		(argument_class->flags & VIPS_ARGUMENT_OUTPUT) &&
583 		argument_instance->assigned &&
584 		G_IS_PARAM_SPEC_OBJECT( pspec ) ) {
585 		GObject *value;
586 
587 		/* This will up the ref count for us.
588 		 */
589 		g_object_get( G_OBJECT( object ),
590 			g_param_spec_get_name( pspec ), &value, NULL );
591 	}
592 
593 	return( NULL );
594 }
595 
596 static void
vips_operation_touch(VipsOperation * operation)597 vips_operation_touch( VipsOperation *operation )
598 {
599 	VipsOperationCacheEntry *entry = (VipsOperationCacheEntry *)
600 		g_hash_table_lookup( vips_cache_table, operation );
601 
602 	vips_cache_time += 1;
603 
604 	/* Don't up the time for invalid items -- we want them to fall out of
605 	 * cache.
606 	 */
607 	if( !entry->invalid )
608 		entry->time = vips_cache_time;
609 }
610 
611 /* Ref an operation for the cache. The operation itself, plus all the output
612  * objects it makes.
613  */
614 static void
vips_cache_ref(VipsOperation * operation)615 vips_cache_ref( VipsOperation *operation )
616 {
617 #ifdef DEBUG
618 	printf( "vips_cache_ref: " );
619 	vips_object_print_summary( VIPS_OBJECT( operation ) );
620 #endif /*DEBUG*/
621 
622 	g_object_ref( operation );
623 	(void) vips_argument_map( VIPS_OBJECT( operation ),
624 		vips_object_ref_arg, NULL, NULL );
625 	vips_operation_touch( operation );
626 }
627 
628 static void
vips_cache_invalidate_cb(VipsOperation * operation,VipsOperationCacheEntry * entry)629 vips_cache_invalidate_cb( VipsOperation *operation,
630 	VipsOperationCacheEntry *entry )
631 {
632 #ifdef DEBUG
633 	printf( "vips_cache_invalidate_cb: " );
634 	vips_object_print_summary( VIPS_OBJECT( operation ) );
635 #endif /*DEBUG*/
636 
637 	entry->invalid = TRUE;
638 }
639 
640 static void
vips_cache_insert(VipsOperation * operation)641 vips_cache_insert( VipsOperation *operation )
642 {
643 	VipsOperationCacheEntry *entry = g_new( VipsOperationCacheEntry, 1 );
644 
645 #ifdef VIPS_DEBUG
646 	printf( "vips_cache_insert: adding to cache" );
647 	vips_object_print_dump( VIPS_OBJECT( operation ) );
648 #endif /*VIPS_DEBUG*/
649 
650 	entry->operation = operation;
651 	entry->time = 0;
652 	entry->invalidate_id = 0;
653 	entry->invalid = FALSE;
654 
655 	g_hash_table_insert( vips_cache_table, operation, entry );
656 	vips_cache_ref( operation );
657 
658 	/* If the operation signals "invalidate", we must tag this cache entry
659 	 * for removal.
660 	 */
661 	entry->invalidate_id = g_signal_connect( operation, "invalidate",
662 		G_CALLBACK( vips_cache_invalidate_cb ), entry );
663 }
664 
665 static void *
vips_cache_get_first_fn(void * value,void * a,void * b)666 vips_cache_get_first_fn( void *value, void *a, void *b )
667 {
668 	return( value );
669 }
670 
671 /* Return the first item.
672  */
673 static VipsOperation *
vips_cache_get_first(void)674 vips_cache_get_first( void )
675 {
676 	VipsOperationCacheEntry *entry;
677 
678 	if( vips_cache_table &&
679 		(entry = vips_hash_table_map( vips_cache_table,
680 			vips_cache_get_first_fn, NULL, NULL )) )
681 		return( VIPS_OPERATION( entry->operation ) );
682 
683 	return( NULL );
684 }
685 
686 /**
687  * vips_cache_drop_all:
688  *
689  * Drop the whole operation cache, handy for leak tracking. Also called
690  * automatically on vips_shutdown().
691  */
692 void
vips_cache_drop_all(void)693 vips_cache_drop_all( void )
694 {
695 #ifdef VIPS_DEBUG
696 	printf( "vips_cache_drop_all:\n" );
697 #endif /*VIPS_DEBUG*/
698 
699 	g_mutex_lock( vips_cache_lock );
700 
701 	if( vips_cache_table ) {
702 		VipsOperation *operation;
703 
704 		if( vips__cache_dump )
705 			vips_cache_print_nolock();
706 
707 		/* We can't modify the hash in the callback from
708 		 * g_hash_table_foreach() and friends. Repeatedly drop the
709 		 * first item instead.
710 		 */
711 		while( (operation = vips_cache_get_first()) )
712 			vips_cache_remove( operation );
713 
714 		VIPS_FREEF( g_hash_table_unref, vips_cache_table );
715 	}
716 
717 	g_mutex_unlock( vips_cache_lock );
718 }
719 
720 static void
vips_cache_get_lru_cb(VipsOperation * key,VipsOperationCacheEntry * value,VipsOperationCacheEntry ** best)721 vips_cache_get_lru_cb( VipsOperation *key, VipsOperationCacheEntry *value,
722 	VipsOperationCacheEntry **best )
723 {
724 	if( !*best ||
725 		(*best)->time > value->time )
726 		*best = value;
727 }
728 
729 /* Get the least-recently-used cache item.
730  *
731  * TODO ... will this be too expensive? probably not
732  */
733 static VipsOperation *
vips_cache_get_lru(void)734 vips_cache_get_lru( void )
735 {
736 	VipsOperationCacheEntry *entry;
737 
738 	entry = NULL;
739 	g_hash_table_foreach( vips_cache_table,
740 		(GHFunc) vips_cache_get_lru_cb, &entry );
741 
742 	if( entry )
743 		return( entry->operation );
744 
745 	return( NULL );
746 }
747 
748 /* Is the cache full? Drop until it's not.
749  */
750 static void
vips_cache_trim(void)751 vips_cache_trim( void )
752 {
753 	VipsOperation *operation;
754 
755 	g_mutex_lock( vips_cache_lock );
756 
757 	while( vips_cache_table &&
758 		(g_hash_table_size( vips_cache_table ) > vips_cache_max ||
759 		vips_tracked_get_files() > vips_cache_max_files ||
760 		vips_tracked_get_mem() > vips_cache_max_mem) &&
761 		(operation = vips_cache_get_lru()) ) {
762 #ifdef DEBUG
763 		printf( "vips_cache_trim: trimming " );
764 		vips_object_print_summary( VIPS_OBJECT( operation ) );
765 #endif /*DEBUG*/
766 
767 		vips_cache_remove( operation );
768 	}
769 
770 	g_mutex_unlock( vips_cache_lock );
771 }
772 
773 /**
774  * vips_cache_operation_lookup:
775  * @operation: (transfer none): pointer to operation to lookup
776  *
777  * Look up an unbuilt @operation in the cache. If we get a hit, ref and
778  * return the old operation. If there's no hit, return NULL.
779  *
780  * Returns: (transfer full): the cache hit, if any.
781  */
782 VipsOperation *
vips_cache_operation_lookup(VipsOperation * operation)783 vips_cache_operation_lookup( VipsOperation *operation )
784 {
785 	VipsOperationCacheEntry *hit;
786 	VipsOperation *result;
787 
788 	g_assert( VIPS_IS_OPERATION( operation ) );
789 	g_assert( !VIPS_OBJECT( operation )->constructed );
790 
791 #ifdef VIPS_DEBUG
792 	printf( "vips_cache_operation_lookup: " );
793 	vips_object_print_dump( VIPS_OBJECT( operation ) );
794 #endif /*VIPS_DEBUG*/
795 
796 	g_mutex_lock( vips_cache_lock );
797 
798 	result = NULL;
799 
800 	if( (hit = g_hash_table_lookup( vips_cache_table, operation )) ) {
801 		if( hit->invalid ) {
802 			/* There but has been tagged for removal.
803 			 */
804 			vips_cache_remove( hit->operation );
805 			hit = NULL;
806 		}
807 		else {
808 			if( vips__cache_trace ) {
809 				printf( "vips cache*: " );
810 				vips_object_print_summary(
811 					VIPS_OBJECT( operation ) );
812 			}
813 
814 			result = hit->operation;
815 			vips_cache_ref( result );
816 		}
817 	}
818 
819 	g_mutex_unlock( vips_cache_lock );
820 
821 #ifdef VIPS_DEBUG
822 	printf( "vips_cache_operation_lookup: result = %p\n", result );
823 #endif /*VIPS_DEBUG*/
824 
825 	return( result );
826 }
827 
828 /**
829  * vips_cache_operation_add:
830  * @operation: (transfer none): pointer to operation to add
831  *
832  * Add a built operation to the cache. The cache will ref the operation.
833  */
834 void
vips_cache_operation_add(VipsOperation * operation)835 vips_cache_operation_add( VipsOperation *operation )
836 {
837 	g_assert( VIPS_OBJECT( operation )->constructed );
838 
839 	g_mutex_lock( vips_cache_lock );
840 
841 #ifdef VIPS_DEBUG
842 	printf( "vips_cache_operation_add: adding " );
843 	vips_object_print_dump( VIPS_OBJECT( operation ) );
844 #endif /*VIPS_DEBUG*/
845 
846 	/* If two threads call the same operation at the same time,
847 	 * we can get multiple adds. Let the first one win. See
848 	 * https://github.com/libvips/libvips/pull/181
849 	 */
850 	if( !g_hash_table_lookup( vips_cache_table, operation ) ) {
851 		VipsOperationFlags flags =
852 			vips_operation_get_flags( operation );
853 		gboolean nocache = flags & VIPS_OPERATION_NOCACHE;
854 
855 		/* Has to be after _build() so we can see output args.
856 		 */
857 		if( vips__cache_trace ) {
858 			if( nocache )
859 				printf( "vips cache : " );
860 			else
861 				printf( "vips cache+: " );
862 			vips_object_print_summary( VIPS_OBJECT( operation ) );
863 		}
864 
865 		if( !nocache )
866 			vips_cache_insert( operation );
867 	}
868 
869 	g_mutex_unlock( vips_cache_lock );
870 
871 	vips_cache_trim();
872 }
873 
874 /**
875  * vips_cache_operation_buildp: (skip)
876  * @operation: pointer to operation to lookup
877  *
878  * Look up @operation in the cache. If we get a hit, unref @operation, ref the
879  * old one and return that through the argument pointer.
880  *
881  * If we miss, build and add @operation.
882  *
883  * Returns: 0 on success, or -1 on error.
884  */
885 int
vips_cache_operation_buildp(VipsOperation ** operation)886 vips_cache_operation_buildp( VipsOperation **operation )
887 {
888 	VipsOperation *hit;
889 
890 	g_assert( VIPS_IS_OPERATION( *operation ) );
891 
892 #ifdef VIPS_DEBUG
893 	printf( "vips_cache_operation_buildp: " );
894 	vips_object_print_dump( VIPS_OBJECT( *operation ) );
895 #endif /*VIPS_DEBUG*/
896 
897 	if( (hit = vips_cache_operation_lookup( *operation )) ) {
898 #ifdef VIPS_DEBUG
899 		printf( "vips_cache_operation_buildp: cache hit %p\n", hit );
900 #endif /*VIPS_DEBUG*/
901 
902 		g_object_unref( *operation );
903 		*operation = hit;
904 	}
905 	else {
906 #ifdef VIPS_DEBUG
907 		printf( "vips_cache_operation_buildp: cache miss, building\n" );
908 #endif /*VIPS_DEBUG*/
909 
910 		if( vips_object_build( VIPS_OBJECT( *operation ) ) )
911 			return( -1 );
912 
913 		vips_cache_operation_add( *operation );
914 	}
915 
916 	return( 0 );
917 }
918 
919 /**
920  * vips_cache_operation_build:
921  * @operation: (transfer none): operation to lookup
922  *
923  * A binding-friendly version of vips_cache_operation_buildp().
924  *
925  * After calling this, @operation has the same ref count as when it went in,
926  * and the result must be freed with vips_object_unref_outputs() and
927  * g_object_unref().
928  *
929  * Returns: (transfer full): The built operation.
930  */
931 VipsOperation *
vips_cache_operation_build(VipsOperation * operation)932 vips_cache_operation_build( VipsOperation *operation )
933 {
934 	VipsOperation *orig_operation = operation;
935 
936 	/* Stop it being unreffed for us on hit.
937 	 */
938 	g_object_ref( orig_operation );
939 
940 	if( vips_cache_operation_buildp( &operation ) ) {
941 		g_object_unref( orig_operation );
942 
943 		return( NULL );
944 	}
945 
946 	return( operation );
947 }
948 
949 /**
950  * vips_cache_set_max:
951  * @max: maximum number of operation to cache
952  *
953  * Set the maximum number of operations we keep in cache.
954  */
955 void
vips_cache_set_max(int max)956 vips_cache_set_max( int max )
957 {
958 	vips_cache_max = max;
959 	vips_cache_trim();
960 }
961 
962 /**
963  * vips_cache_set_max_mem:
964  * @max_mem: maximum amount of tracked memory we use
965  *
966  * Set the maximum amount of tracked memory we allow before we start dropping
967  * cached operations. See vips_tracked_get_mem().
968  *
969  * libvips only tracks memory it allocates, it can't track memory allocated by
970  * external libraries. If you use an operation like vips_magickload(), most of
971  * the memory it uses won't be included.
972  *
973  * See also: vips_tracked_get_mem().
974  */
975 void
vips_cache_set_max_mem(size_t max_mem)976 vips_cache_set_max_mem( size_t max_mem )
977 {
978 	vips_cache_max_mem = max_mem;
979 	vips_cache_trim();
980 }
981 
982 /**
983  * vips_cache_get_max:
984  *
985  * Get the maximum number of operations we keep in cache.
986  *
987  * Returns: the maximum number of operations we keep in cache
988  */
989 int
vips_cache_get_max(void)990 vips_cache_get_max( void )
991 {
992 	return( vips_cache_max );
993 }
994 
995 /**
996  * vips_cache_get_size:
997  *
998  * Get the current number of operations in cache.
999  *
1000  * Returns: get the current number of operations in cache.
1001  */
1002 int
vips_cache_get_size(void)1003 vips_cache_get_size( void )
1004 {
1005 	guint size;
1006 
1007 	g_mutex_lock( vips_cache_lock );
1008 
1009 	size = 0;
1010 	if( vips_cache_table )
1011 		size = g_hash_table_size( vips_cache_table );
1012 
1013 	g_mutex_unlock( vips_cache_lock );
1014 
1015 	return( size );
1016 }
1017 
1018 /**
1019  * vips_cache_get_max_mem:
1020  *
1021  * Get the maximum amount of tracked memory we allow before we start dropping
1022  * cached operations. See vips_tracked_get_mem().
1023  *
1024  * See also: vips_tracked_get_mem().
1025  *
1026  * Returns: the maximum amount of tracked memory we allow
1027  */
1028 size_t
vips_cache_get_max_mem(void)1029 vips_cache_get_max_mem( void )
1030 {
1031 	return( vips_cache_max_mem );
1032 }
1033 
1034 /**
1035  * vips_cache_get_max_files:
1036  *
1037  * Get the maximum number of tracked files we allow before we start dropping
1038  * cached operations. See vips_tracked_get_files().
1039  *
1040  * libvips only tracks file descriptors it allocates, it can't track ones
1041  * allocated by external libraries. If you use an operation like
1042  * vips_magickload(), most of the descriptors it uses won't be included.
1043  *
1044  * See also: vips_tracked_get_files().
1045  *
1046  * Returns: the maximum number of tracked files we allow
1047  */
1048 int
vips_cache_get_max_files(void)1049 vips_cache_get_max_files( void )
1050 {
1051 	return( vips_cache_max_files );
1052 }
1053 
1054 /**
1055  * vips_cache_set_max_files:
1056  * @max_files: max open files we allow
1057  *
1058  * Set the maximum number of tracked files we allow before we start dropping
1059  * cached operations. See vips_tracked_get_files().
1060  *
1061  * See also: vips_tracked_get_files().
1062  */
1063 void
vips_cache_set_max_files(int max_files)1064 vips_cache_set_max_files( int max_files )
1065 {
1066 	vips_cache_max_files = max_files;
1067 	vips_cache_trim();
1068 }
1069 
1070 /**
1071  * vips_cache_set_dump:
1072  * @dump: if %TRUE, dump the operation cache on exit
1073  *
1074  * Handy for debugging. Print the operation cache to stdout just before exit.
1075  *
1076  * See also: vips_cache_set_trace().
1077  */
1078 void
vips_cache_set_dump(gboolean dump)1079 vips_cache_set_dump( gboolean dump )
1080 {
1081 	vips__cache_dump = dump;
1082 }
1083 
1084 /**
1085  * vips_cache_set_trace:
1086  * @trace: if %TRUE, trace the operation cache
1087  *
1088  * Handy for debugging. Print operation cache actions to stdout as we run.
1089  *
1090  * You can set the environment variable `VIPS_TRACE` to turn this option on, or
1091  * use the command-line flag `--vips-cache-trace`.
1092  *
1093  * See also: vips_cache_set_dump().
1094  */
1095 void
vips_cache_set_trace(gboolean trace)1096 vips_cache_set_trace( gboolean trace )
1097 {
1098 	vips__cache_trace = trace;
1099 }
1100