mirror of
https://git.openldap.org/openldap/openldap.git
synced 2024-12-21 03:10:25 +08:00
Reworked again the caching in case of failure.
Now operations that set the status of an entry to CREATING (add.c, modrdn.c) need to set it to COMMIT, by calling cache_entry_commit, before returning the entry itself, otherwise the entry is removed from the cache and its private data is freed. Should fix crashes due to add failures as in ITS#1245
This commit is contained in:
parent
aec4430d59
commit
9ee9f1e0e1
@ -354,7 +354,12 @@ ldbm_back_add(
|
|||||||
|
|
||||||
send_ldap_result( conn, op, LDAP_SUCCESS,
|
send_ldap_result( conn, op, LDAP_SUCCESS,
|
||||||
NULL, NULL, NULL, NULL );
|
NULL, NULL, NULL, NULL );
|
||||||
|
|
||||||
|
/* marks the entry as committed, so it is added to the cache;
|
||||||
|
* otherwise it is removed from the cache, but not destroyed;
|
||||||
|
* it will be destroyed by the caller */
|
||||||
rc = 0;
|
rc = 0;
|
||||||
|
cache_entry_commit( e );
|
||||||
|
|
||||||
return_results:;
|
return_results:;
|
||||||
if (p != NULL) {
|
if (p != NULL) {
|
||||||
@ -368,10 +373,8 @@ return_results:;
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ( rc ) {
|
if ( rc ) {
|
||||||
/* FIXME: remove from cache? */
|
/* in case of error, writer lock is freed
|
||||||
cache_entry_private_destroy_mark( e );
|
* and entry's private data is destroyed */
|
||||||
|
|
||||||
/* free entry and writer lock */
|
|
||||||
cache_return_entry_w( &li->li_cache, e );
|
cache_return_entry_w( &li->li_cache, e );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,9 +29,9 @@ typedef struct ldbm_entry_info {
|
|||||||
int lei_state; /* for the cache */
|
int lei_state; /* for the cache */
|
||||||
#define CACHE_ENTRY_UNDEFINED 0
|
#define CACHE_ENTRY_UNDEFINED 0
|
||||||
#define CACHE_ENTRY_CREATING 1
|
#define CACHE_ENTRY_CREATING 1
|
||||||
#define CACHE_ENTRY_READY 2
|
#define CACHE_ENTRY_READY 2
|
||||||
#define CACHE_ENTRY_DELETED 3
|
#define CACHE_ENTRY_DELETED 3
|
||||||
#define CACHE_ENTRY_DESTROY_PRIVATE 4
|
#define CACHE_ENTRY_COMMITTED 4
|
||||||
|
|
||||||
int lei_refcnt; /* # threads ref'ing this entry */
|
int lei_refcnt; /* # threads ref'ing this entry */
|
||||||
Entry *lei_lrunext; /* for cache lru list */
|
Entry *lei_lrunext; /* for cache lru list */
|
||||||
@ -136,17 +136,20 @@ cache_entry_private_init( Entry*e )
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* assumes that the entry is write-locked;marks it i a manner that
|
* marks an entry in CREATING state as committed, so it is really returned
|
||||||
* makes e_private be destroyed at the following cache_return_entry_w,
|
* to the cache. Otherwise an entry in CREATING state is removed.
|
||||||
|
* Makes e_private be destroyed at the following cache_return_entry_w,
|
||||||
* but lets the entry untouched (owned by someone else)
|
* but lets the entry untouched (owned by someone else)
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
cache_entry_private_destroy_mark( Entry *e )
|
cache_entry_commit( Entry *e )
|
||||||
{
|
{
|
||||||
assert( e );
|
assert( e );
|
||||||
assert( e->e_private );
|
assert( e->e_private );
|
||||||
|
assert( LEI(e)->lei_state == CACHE_ENTRY_CREATING );
|
||||||
|
/* assert( LEI(e)->lei_refcnt == 1 ); */
|
||||||
|
|
||||||
LEI(e)->lei_state = CACHE_ENTRY_DESTROY_PRIVATE;
|
LEI(e)->lei_state = CACHE_ENTRY_COMMITTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@ -165,7 +168,7 @@ void
|
|||||||
cache_return_entry_rw( Cache *cache, Entry *e, int rw )
|
cache_return_entry_rw( Cache *cache, Entry *e, int rw )
|
||||||
{
|
{
|
||||||
ID id;
|
ID id;
|
||||||
int refcnt;
|
int refcnt, freeit = 1;
|
||||||
|
|
||||||
/* set cache mutex */
|
/* set cache mutex */
|
||||||
ldap_pvt_thread_mutex_lock( &cache->c_mutex );
|
ldap_pvt_thread_mutex_lock( &cache->c_mutex );
|
||||||
@ -177,7 +180,18 @@ cache_return_entry_rw( Cache *cache, Entry *e, int rw )
|
|||||||
id = e->e_id;
|
id = e->e_id;
|
||||||
refcnt = --LEI(e)->lei_refcnt;
|
refcnt = --LEI(e)->lei_refcnt;
|
||||||
|
|
||||||
if ( LEI(e)->lei_state == CACHE_ENTRY_CREATING ) {
|
/*
|
||||||
|
* if the entry is returned when in CREATING state, it is deleted
|
||||||
|
* but not freed because it may belong to someone else (do_add,
|
||||||
|
* for instance)
|
||||||
|
*/
|
||||||
|
if ( LEI(e)->lei_state == CACHE_ENTRY_CREATING ) {
|
||||||
|
cache_delete_entry_internal( cache, e );
|
||||||
|
freeit = 0;
|
||||||
|
/* now the entry is in DELETED state */
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( LEI(e)->lei_state == CACHE_ENTRY_COMMITTED ) {
|
||||||
LEI(e)->lei_state = CACHE_ENTRY_READY;
|
LEI(e)->lei_state = CACHE_ENTRY_READY;
|
||||||
|
|
||||||
/* free cache mutex */
|
/* free cache mutex */
|
||||||
@ -194,8 +208,7 @@ cache_return_entry_rw( Cache *cache, Entry *e, int rw )
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
} else if ( LEI(e)->lei_state == CACHE_ENTRY_DELETED
|
} else if ( LEI(e)->lei_state == CACHE_ENTRY_DELETED ) {
|
||||||
|| LEI(e)->lei_state == CACHE_ENTRY_DESTROY_PRIVATE ) {
|
|
||||||
if( refcnt > 0 ) {
|
if( refcnt > 0 ) {
|
||||||
/* free cache mutex */
|
/* free cache mutex */
|
||||||
ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
|
ldap_pvt_thread_mutex_unlock( &cache->c_mutex );
|
||||||
@ -212,10 +225,8 @@ cache_return_entry_rw( Cache *cache, Entry *e, int rw )
|
|||||||
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
int state = LEI(e)->lei_state;
|
|
||||||
|
|
||||||
cache_entry_private_destroy( e );
|
cache_entry_private_destroy( e );
|
||||||
if ( state == CACHE_ENTRY_DELETED ) {
|
if ( freeit ) {
|
||||||
entry_free( e );
|
entry_free( e );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -274,6 +274,9 @@ id2entry_rw( Backend *be, ID id, int rw )
|
|||||||
rw ? "w" : "r", id, (unsigned long) e );
|
rw ? "w" : "r", id, (unsigned long) e );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* marks the entry as committed, so it will get added to the cache
|
||||||
|
* when the lock is released */
|
||||||
|
cache_entry_commit( e );
|
||||||
|
|
||||||
return( e );
|
return( e );
|
||||||
}
|
}
|
||||||
|
@ -847,6 +847,7 @@ ldbm_back_modrdn(
|
|||||||
|
|
||||||
goto return_results;
|
goto return_results;
|
||||||
}
|
}
|
||||||
|
rc = -1;
|
||||||
|
|
||||||
(void) cache_update_entry( &li->li_cache, e );
|
(void) cache_update_entry( &li->li_cache, e );
|
||||||
|
|
||||||
@ -856,7 +857,6 @@ ldbm_back_modrdn(
|
|||||||
|
|
||||||
/* id2entry index */
|
/* id2entry index */
|
||||||
if ( id2entry_add( be, e ) != 0 ) {
|
if ( id2entry_add( be, e ) != 0 ) {
|
||||||
entry_free( e );
|
|
||||||
send_ldap_result( conn, op, LDAP_OTHER,
|
send_ldap_result( conn, op, LDAP_OTHER,
|
||||||
NULL, "entry update failed", NULL, NULL );
|
NULL, "entry update failed", NULL, NULL );
|
||||||
goto return_results;
|
goto return_results;
|
||||||
@ -865,6 +865,7 @@ ldbm_back_modrdn(
|
|||||||
send_ldap_result( conn, op, LDAP_SUCCESS,
|
send_ldap_result( conn, op, LDAP_SUCCESS,
|
||||||
NULL, NULL, NULL, NULL );
|
NULL, NULL, NULL, NULL );
|
||||||
rc = 0;
|
rc = 0;
|
||||||
|
cache_entry_commit( e );
|
||||||
|
|
||||||
return_results:
|
return_results:
|
||||||
if( new_dn != NULL ) free( new_dn );
|
if( new_dn != NULL ) free( new_dn );
|
||||||
@ -917,5 +918,10 @@ return_results:
|
|||||||
|
|
||||||
/* free entry and writer lock */
|
/* free entry and writer lock */
|
||||||
cache_return_entry_w( &li->li_cache, e );
|
cache_return_entry_w( &li->li_cache, e );
|
||||||
|
if ( rc ) {
|
||||||
|
/* if rc != 0 the entry is uncached and its private data
|
||||||
|
* is destroyed; the entry must be freed */
|
||||||
|
entry_free( e );
|
||||||
|
}
|
||||||
return( rc );
|
return( rc );
|
||||||
}
|
}
|
||||||
|
@ -51,7 +51,7 @@ int cache_update_entry LDAP_P(( Cache *cache, Entry *e ));
|
|||||||
void cache_return_entry_rw LDAP_P(( Cache *cache, Entry *e, int rw ));
|
void cache_return_entry_rw LDAP_P(( Cache *cache, Entry *e, int rw ));
|
||||||
#define cache_return_entry_r(c, e) cache_return_entry_rw((c), (e), 0)
|
#define cache_return_entry_r(c, e) cache_return_entry_rw((c), (e), 0)
|
||||||
#define cache_return_entry_w(c, e) cache_return_entry_rw((c), (e), 1)
|
#define cache_return_entry_w(c, e) cache_return_entry_rw((c), (e), 1)
|
||||||
void cache_entry_private_destroy_mark LDAP_P(( Entry *e ));
|
void cache_entry_commit LDAP_P(( Entry *e ));
|
||||||
|
|
||||||
ID cache_find_entry_dn2id LDAP_P(( Backend *be, Cache *cache, const char *dn ));
|
ID cache_find_entry_dn2id LDAP_P(( Backend *be, Cache *cache, const char *dn ));
|
||||||
ID cache_find_entry_ndn2id LDAP_P(( Backend *be, Cache *cache, const char *ndn ));
|
ID cache_find_entry_ndn2id LDAP_P(( Backend *be, Cache *cache, const char *ndn ));
|
||||||
|
Loading…
Reference in New Issue
Block a user