⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cache.c

📁 ldap服务器源码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* cache.c - routines to maintain an in-core cache of entries *//* $OpenLDAP: pkg/ldap/servers/slapd/back-bdb/cache.c,v 1.88.2.21 2007/01/25 12:42:38 hyc Exp $ *//* This work is part of OpenLDAP Software <http://www.openldap.org/>. * * Copyright 2000-2007 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * <http://www.OpenLDAP.org/license.html>. */#include "portable.h"#include <stdio.h>#include <ac/errno.h>#include <ac/string.h>#include <ac/socket.h>#include "slap.h"#include "back-bdb.h"#include "ldap_rq.h"#ifdef BDB_HIER#define bdb_cache_lru_add	hdb_cache_lru_add#endifstatic void bdb_cache_lru_add( struct bdb_info *bdb, EntryInfo *ei );static int	bdb_cache_delete_internal(Cache *cache, EntryInfo *e, int decr);#ifdef LDAP_DEBUG#ifdef SLAPD_UNUSEDstatic void	bdb_lru_print(Cache *cache);#endif#endifstatic EntryInfo *bdb_cache_entryinfo_new( Cache *cache ){	EntryInfo *ei = NULL;	if ( cache->c_eifree ) {		ldap_pvt_thread_rdwr_wlock( &cache->c_rwlock );		if ( cache->c_eifree ) {			ei = cache->c_eifree;			cache->c_eifree = ei->bei_lrunext;		}		ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock );	}	if ( ei ) {		ei->bei_lrunext = NULL;		ei->bei_state = 0;	} else {		ei = ch_calloc(1, sizeof(struct bdb_entry_info));		ldap_pvt_thread_mutex_init( &ei->bei_kids_mutex );	}	return ei;}/* Atomically release and reacquire a lock */intbdb_cache_entry_db_relock(	DB_ENV *env,	u_int32_t locker,	EntryInfo *ei,	int rw,	int tryOnly,	DB_LOCK *lock ){#ifdef NO_THREADS	return 0;#else	int	rc;	DBT	lockobj;	DB_LOCKREQ list[2];	if ( !lock ) return 0;	lockobj.data = &ei->bei_id;	lockobj.size = sizeof(ei->bei_id) + 1;	list[0].op = DB_LOCK_PUT;	list[0].lock = *lock;	list[1].op = DB_LOCK_GET;	list[1].lock = *lock;	list[1].mode = rw ? DB_LOCK_WRITE : DB_LOCK_READ;	list[1].obj = &lockobj;	rc = env->lock_vec(env, locker, tryOnly ? DB_LOCK_NOWAIT : 0,		list, 2, NULL );	if (rc && !tryOnly) {		Debug( LDAP_DEBUG_TRACE,			"bdb_cache_entry_db_relock: entry %ld, rw %d, rc %d\n",			ei->bei_id, rw, rc );	} else {		*lock = list[1].lock;	}	return rc;#endif}static intbdb_cache_entry_db_lock( DB_ENV *env, u_int32_t locker, EntryInfo *ei,	int rw, int tryOnly, DB_LOCK *lock ){#ifdef NO_THREADS	return 0;#else	int       rc;	DBT       lockobj;	int       db_rw;	if ( !lock ) return 0;	if (rw)		db_rw = DB_LOCK_WRITE;	else		db_rw = DB_LOCK_READ;	lockobj.data = &ei->bei_id;	lockobj.size = sizeof(ei->bei_id) + 1;	rc = LOCK_GET(env, locker, tryOnly ? DB_LOCK_NOWAIT : 0,					&lockobj, db_rw, lock);	if (rc && !tryOnly) {		Debug( LDAP_DEBUG_TRACE,			"bdb_cache_entry_db_lock: entry %ld, rw %d, rc %d\n",			ei->bei_id, rw, rc );	}	return rc;#endif /* NO_THREADS */}intbdb_cache_entry_db_unlock ( DB_ENV *env, DB_LOCK *lock ){#ifdef NO_THREADS	return 0;#else	int rc;	if ( !lock || lock->mode == DB_LOCK_NG ) return 0;	rc = LOCK_PUT ( env, lock );	return rc;#endif}static intbdb_cache_entryinfo_destroy( EntryInfo *e ){	ldap_pvt_thread_mutex_destroy( &e->bei_kids_mutex );	free( e->bei_nrdn.bv_val );#ifdef BDB_HIER	free( e->bei_rdn.bv_val );#endif	free( e );	return 0;}#define LRU_DELETE( cache, ei ) do { \	if ( (ei)->bei_lruprev != NULL ) { \		(ei)->bei_lruprev->bei_lrunext = (ei)->bei_lrunext; \	} else { \		(cache)->c_lruhead = (ei)->bei_lrunext; \	} \	if ( (ei)->bei_lrunext != NULL ) { \		(ei)->bei_lrunext->bei_lruprev = (ei)->bei_lruprev; \	} else { \		(cache)->c_lrutail = (ei)->bei_lruprev; \	} \	(ei)->bei_lrunext = (ei)->bei_lruprev = NULL; \} while(0)#define LRU_ADD( cache, ei ) do { \	(ei)->bei_lrunext = (cache)->c_lruhead; \	if ( (ei)->bei_lrunext != NULL ) { \		(ei)->bei_lrunext->bei_lruprev = (ei); \	} \	(cache)->c_lruhead = (ei); \	(ei)->bei_lruprev = NULL; \	if ( !ldap_pvt_thread_mutex_trylock( &(cache)->lru_tail_mutex )) { \		if ( (cache)->c_lrutail == NULL ) \			(cache)->c_lrutail = (ei); \		ldap_pvt_thread_mutex_unlock( &(cache)->lru_tail_mutex ); \	} \} while(0)/* Do a length-ordered sort on normalized RDNs */static intbdb_rdn_cmp( const void *v_e1, const void *v_e2 ){	const EntryInfo *e1 = v_e1, *e2 = v_e2;	int rc = e1->bei_nrdn.bv_len - e2->bei_nrdn.bv_len;	if (rc == 0) {		rc = strncmp( e1->bei_nrdn.bv_val, e2->bei_nrdn.bv_val,			e1->bei_nrdn.bv_len );	}	return rc;}static intbdb_id_cmp( const void *v_e1, const void *v_e2 ){	const EntryInfo *e1 = v_e1, *e2 = v_e2;	return e1->bei_id - e2->bei_id;}/* Create an entryinfo in the cache. Caller must release the locks later. */static intbdb_entryinfo_add_internal(	struct bdb_info *bdb,	EntryInfo *ei,	EntryInfo **res ){	EntryInfo *ei2 = NULL;	*res = NULL;	ei2 = bdb_cache_entryinfo_new( &bdb->bi_cache );	ldap_pvt_thread_rdwr_wlock( &bdb->bi_cache.c_rwlock );	bdb_cache_entryinfo_lock( ei->bei_parent );	ei2->bei_id = ei->bei_id;	ei2->bei_parent = ei->bei_parent;#ifdef BDB_HIER	ei2->bei_rdn = ei->bei_rdn;#endif#ifdef SLAP_ZONE_ALLOC	ei2->bei_bdb = bdb;#endif	/* Add to cache ID tree */	if (avl_insert( &bdb->bi_cache.c_idtree, ei2, bdb_id_cmp, avl_dup_error )) {		EntryInfo *eix;		eix = avl_find( bdb->bi_cache.c_idtree, ei2, bdb_id_cmp );		bdb_cache_entryinfo_destroy( ei2 );		ei2 = eix;#ifdef BDB_HIER		/* It got freed above because its value was		 * assigned to ei2.		 */		ei->bei_rdn.bv_val = NULL;#endif	} else {		bdb->bi_cache.c_eiused++;		ber_dupbv( &ei2->bei_nrdn, &ei->bei_nrdn );		/* This is a new leaf node. But if parent had no kids, then it was		 * a leaf and we would be decrementing that. So, only increment if		 * the parent already has kids.		 */		if ( ei->bei_parent->bei_kids || !ei->bei_parent->bei_id )			bdb->bi_cache.c_leaves++;		avl_insert( &ei->bei_parent->bei_kids, ei2, bdb_rdn_cmp,			avl_dup_error );#ifdef BDB_HIER		ei->bei_parent->bei_ckids++;#endif	}	*res = ei2;	return 0;}/* Find the EntryInfo for the requested DN. If the DN cannot be found, return * the info for its closest ancestor. *res should be NULL to process a * complete DN starting from the tree root. Otherwise *res must be the * immediate parent of the requested DN, and only the RDN will be searched. * The EntryInfo is locked upon return and must be unlocked by the caller. */intbdb_cache_find_ndn(	Operation	*op,	DB_TXN		*txn,	struct berval	*ndn,	EntryInfo	**res ){	struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;	EntryInfo	ei, *eip, *ei2;	int rc = 0;	char *ptr;	/* this function is always called with normalized DN */	if ( *res ) {		/* we're doing a onelevel search for an RDN */		ei.bei_nrdn.bv_val = ndn->bv_val;		ei.bei_nrdn.bv_len = dn_rdnlen( op->o_bd, ndn );		eip = *res;	} else {		/* we're searching a full DN from the root */		ptr = ndn->bv_val + ndn->bv_len - op->o_bd->be_nsuffix[0].bv_len;		ei.bei_nrdn.bv_val = ptr;		ei.bei_nrdn.bv_len = op->o_bd->be_nsuffix[0].bv_len;		/* Skip to next rdn if suffix is empty */		if ( ei.bei_nrdn.bv_len == 0 ) {			for (ptr = ei.bei_nrdn.bv_val - 2; ptr > ndn->bv_val				&& !DN_SEPARATOR(*ptr); ptr--) /* empty */;			if ( ptr >= ndn->bv_val ) {				if (DN_SEPARATOR(*ptr)) ptr++;				ei.bei_nrdn.bv_len = ei.bei_nrdn.bv_val - ptr;				ei.bei_nrdn.bv_val = ptr;			}		}		eip = &bdb->bi_cache.c_dntree;	}		for ( bdb_cache_entryinfo_lock( eip ); eip; ) {		ei.bei_parent = eip;		ei2 = (EntryInfo *)avl_find( eip->bei_kids, &ei, bdb_rdn_cmp );		if ( !ei2 ) {			int len = ei.bei_nrdn.bv_len;							if ( BER_BVISEMPTY( ndn )) {				*res = eip;				return LDAP_SUCCESS;			}			ei.bei_nrdn.bv_len = ndn->bv_len -				(ei.bei_nrdn.bv_val - ndn->bv_val);			bdb_cache_entryinfo_unlock( eip );			rc = bdb_dn2id( op, txn, &ei.bei_nrdn, &ei );			if (rc) {				bdb_cache_entryinfo_lock( eip );				*res = eip;				return rc;			}			/* DN exists but needs to be added to cache */			ei.bei_nrdn.bv_len = len;			rc = bdb_entryinfo_add_internal( bdb, &ei, &ei2 );			/* add_internal left eip and c_rwlock locked */			ldap_pvt_thread_rdwr_wunlock( &bdb->bi_cache.c_rwlock );			if ( rc ) {				*res = eip;				return rc;			}		} else if ( ei2->bei_state & CACHE_ENTRY_DELETED ) {			/* In the midst of deleting? Give it a chance to			 * complete.			 */			bdb_cache_entryinfo_unlock( eip );			ldap_pvt_thread_yield();			bdb_cache_entryinfo_lock( eip );			*res = eip;			return DB_NOTFOUND;		}		bdb_cache_entryinfo_unlock( eip );		bdb_cache_entryinfo_lock( ei2 );		eip = ei2;		/* Advance to next lower RDN */		for (ptr = ei.bei_nrdn.bv_val - 2; ptr > ndn->bv_val			&& !DN_SEPARATOR(*ptr); ptr--) /* empty */;		if ( ptr >= ndn->bv_val ) {			if (DN_SEPARATOR(*ptr)) ptr++;			ei.bei_nrdn.bv_len = ei.bei_nrdn.bv_val - ptr - 1;			ei.bei_nrdn.bv_val = ptr;		}		if ( ptr < ndn->bv_val ) {			*res = eip;			break;		}	}	return rc;}#ifdef BDB_HIER/* Walk up the tree from a child node, looking for an ID that's already * been linked into the cache. */inthdb_cache_find_parent(	Operation *op,	DB_TXN *txn,	u_int32_t	locker,	ID id,	EntryInfo **res ){	struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;	EntryInfo ei, eip, *ei2 = NULL, *ein = NULL, *eir = NULL;	int rc;	int addlru = 0;	ei.bei_id = id;	ei.bei_kids = NULL;	ei.bei_ckids = 0;	for (;;) {		rc = hdb_dn2id_parent( op, txn, locker, &ei, &eip.bei_id );		if ( rc ) break;		/* Save the previous node, if any */		ei2 = ein;		/* Create a new node for the current ID */		ein = bdb_cache_entryinfo_new( &bdb->bi_cache );		ein->bei_id = ei.bei_id;		ein->bei_kids = ei.bei_kids;		ein->bei_nrdn = ei.bei_nrdn;		ein->bei_rdn = ei.bei_rdn;		ein->bei_ckids = ei.bei_ckids;#ifdef SLAP_ZONE_ALLOC		ein->bei_bdb = bdb;#endif		ei.bei_ckids = 0;				/* This node is not fully connected yet */		ein->bei_state = CACHE_ENTRY_NOT_LINKED;		/* Insert this node into the ID tree */		ldap_pvt_thread_rdwr_wlock( &bdb->bi_cache.c_rwlock );		if ( avl_insert( &bdb->bi_cache.c_idtree, (caddr_t)ein,			bdb_id_cmp, avl_dup_error ) ) {			/* Someone else created this node just before us.			 * Free our new copy and use the existing one.			 */			bdb_cache_entryinfo_destroy( ein );			ein = (EntryInfo *)avl_find( bdb->bi_cache.c_idtree,				(caddr_t) &ei, bdb_id_cmp );						/* Link in any kids we've already processed */			if ( ei2 ) {				bdb_cache_entryinfo_lock( ein );				avl_insert( &ein->bei_kids, (caddr_t)ei2,					bdb_rdn_cmp, avl_dup_error );				ein->bei_ckids++;				bdb_cache_entryinfo_unlock( ein );			}			addlru = 0;		}		/* If this is the first time, save this node		 * to be returned later.		 */		if ( eir == NULL ) eir = ein;		/* If there was a previous node, link it to this one */		if ( ei2 ) ei2->bei_parent = ein;		/* Look for this node's parent */		if ( eip.bei_id ) {			ei2 = (EntryInfo *) avl_find( bdb->bi_cache.c_idtree,					(caddr_t) &eip, bdb_id_cmp );		} else {			ei2 = &bdb->bi_cache.c_dntree;		}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -