+ /* Look for an unused entry to remove */
+ for ( elru = bdb->bi_cache.c_lruhead; elru; elru = elnext ) {
+ elnext = elru->bei_lrunext;
+
+ if ( bdb_cache_entryinfo_trylock( elru ))
+ goto bottom;
+
+ /* This flag implements the clock replacement behavior */
+ if ( elru->bei_state & ( CACHE_ENTRY_REFERENCED )) {
+ elru->bei_state &= ~CACHE_ENTRY_REFERENCED;
+ bdb_cache_entryinfo_unlock( elru );
+ goto bottom;
+ }
+
+ /* If this node is in the process of linking into the cache,
+ * or this node is being deleted, skip it.
+ */
+ if (( elru->bei_state & ( CACHE_ENTRY_NOT_LINKED |
+ CACHE_ENTRY_DELETED | CACHE_ENTRY_LOADING |
+ CACHE_ENTRY_ONELEVEL )) ||
+ elru->bei_finders > 0 ) {
+ bdb_cache_entryinfo_unlock( elru );
+ goto bottom;
+ }
+
+ if ( bdb_cache_entryinfo_trylock( elru->bei_parent )) {
+ bdb_cache_entryinfo_unlock( elru );
+ goto bottom;
+ }
+
+ /* entryinfo is locked */
+ islocked = 1;
+
+ /* If we can successfully writelock it, then
+ * the object is idle.
+ */
+ if ( bdb_cache_entry_db_lock( bdb,
+ bdb->bi_cache.c_txn, elru, 1, 1, lockp ) == 0 ) {
+
+ /* Free entry for this node if it's present */
+ if ( elru->bei_e ) {
+ ecount++;
+
+ /* the cache may have gone over the limit while we
+ * weren't looking, so double check.
+ */
+ if ( !efree && ecount > bdb->bi_cache.c_maxsize )
+ efree = bdb->bi_cache.c_minfree;
+
+ if ( count < efree ) {
+ elru->bei_e->e_private = NULL;
+#ifdef SLAP_ZONE_ALLOC
+ bdb_entry_return( bdb, elru->bei_e, elru->bei_zseq );
+#else
+ bdb_entry_return( elru->bei_e );
+#endif
+ elru->bei_e = NULL;
+ count++;
+ } else {
+ /* Keep this node cached, skip to next */
+ bdb_cache_entry_db_unlock( bdb, lockp );
+ goto next;
+ }
+ }
+ bdb_cache_entry_db_unlock( bdb, lockp );
+
+ /*
+ * If it is a leaf node, and we're over the limit, free it.
+ */
+ if ( elru->bei_kids ) {
+ /* Drop from list, we ignore it... */
+ LRU_DEL( &bdb->bi_cache, elru );
+ } else if ( eicount < eifree ) {
+ /* Too many leaf nodes, free this one */
+ bdb_cache_delete_internal( &bdb->bi_cache, elru, 0 );
+ bdb_cache_delete_cleanup( &bdb->bi_cache, elru );
+ islocked = 0;
+ eicount++;
+ } /* Leave on list until we need to free it */
+ }
+
+next:
+ if ( islocked ) {
+ bdb_cache_entryinfo_unlock( elru );
+ bdb_cache_entryinfo_unlock( elru->bei_parent );
+ }
+
+ if ( count >= efree && eicount >= eifree )
+ break;
+bottom:
+ if ( elnext == bdb->bi_cache.c_lruhead )
+ break;
+#ifdef LDAP_DEBUG
+ iter++;
+#endif
+ }
+
+ if ( count || ecount > bdb->bi_cache.c_cursize ) {
+ ldap_pvt_thread_mutex_lock( &bdb->bi_cache.c_count_mutex );
+ /* HACK: we seem to be losing track, fix up now */
+ if ( ecount > bdb->bi_cache.c_cursize )
+ bdb->bi_cache.c_cursize = ecount;
+ bdb->bi_cache.c_cursize -= count;
+ ldap_pvt_thread_mutex_unlock( &bdb->bi_cache.c_count_mutex );
+ }
+ bdb->bi_cache.c_lruhead = elnext;
+ ldap_pvt_thread_mutex_unlock( &bdb->bi_cache.c_lru_mutex );
+ bdb->bi_cache.c_purging = 0;
+}
+