From f63f46f0b1baf0e7f208b9181b8927f2b2ca5416 Mon Sep 17 00:00:00 2001 From: Howard Chu Date: Wed, 20 Sep 2006 02:43:47 +0000 Subject: [PATCH] Use a single malloc for entry_decode instead of two - partially decode the entry to get nvals first, so the size can be computed. --- servers/slapd/back-bdb/id2entry.c | 48 +++++++++++++--- servers/slapd/back-bdb/tools.c | 94 ++++++++++++++++++++----------- servers/slapd/entry.c | 62 ++++++++++---------- servers/slapd/proto-slap.h | 5 +- servers/slapd/slap.h | 8 ++- 5 files changed, 143 insertions(+), 74 deletions(-) diff --git a/servers/slapd/back-bdb/id2entry.c b/servers/slapd/back-bdb/id2entry.c index 58fafd1cc9..3c5580ea9c 100644 --- a/servers/slapd/back-bdb/id2entry.c +++ b/servers/slapd/back-bdb/id2entry.c @@ -18,6 +18,7 @@ #include #include +#include #include "back-bdb.h" @@ -100,8 +101,9 @@ int bdb_id2entry( DB *db = bdb->bi_id2entry->bdi_db; DBT key, data; DBC *cursor; - struct berval bv; - int rc = 0; + EntryHeader eh; + char buf[16]; + int rc = 0, off; ID nid; *e = NULL; @@ -112,7 +114,7 @@ int bdb_id2entry( BDB_ID2DISK( id, &nid ); DBTzero( &data ); - data.flags = DB_DBT_MALLOC; + data.flags = DB_DBT_USERMEM | DB_DBT_PARTIAL; /* fetch it */ rc = db->cursor( db, tid, &cursor, bdb->bi_db_opflags ); @@ -122,19 +124,47 @@ int bdb_id2entry( if ( !tid && locker ) cursor->locker = locker; + /* Get the nattrs / nvals counts first */ + data.ulen = data.dlen = sizeof(buf); + data.data = buf; rc = cursor->c_get( cursor, &key, &data, DB_SET ); + if ( rc ) goto leave; + + eh.bv.bv_val = buf; + eh.bv.bv_len = data.size; + rc = entry_header( &eh ); + if ( rc ) goto leave; + + /* Get the size */ + data.flags ^= DB_DBT_PARTIAL; + data.ulen = 0; + rc = cursor->c_get( cursor, &key, &data, DB_CURRENT ); + if ( rc != ENOMEM ) goto leave; + + /* Allocate a block and retrieve the data */ + off = eh.data - eh.bv.bv_val; + eh.bv.bv_len = eh.nvals * sizeof( struct berval ) + data.size; + eh.bv.bv_val = ch_malloc( eh.bv.bv_len ); + eh.data = eh.bv.bv_val + eh.nvals * sizeof( struct berval ); + data.data = eh.data; + data.ulen = data.size; + + /* skip past already parsed nattr/nvals */ + eh.data += off; + + rc = cursor->c_get( cursor, &key, &data, DB_CURRENT ); + +leave: cursor->c_close( cursor ); if( rc != 0 ) { return rc; } - DBT2bv( &data, &bv ); - #ifdef SLAP_ZONE_ALLOC - rc = entry_decode(&bv, e, bdb->bi_cache.c_zctx); + rc = entry_decode(&eh, e, bdb->bi_cache.c_zctx); #else - rc = entry_decode(&bv, e); + rc = entry_decode(&eh, e); #endif if( rc == 0 ) { @@ -144,11 +174,11 @@ int bdb_id2entry( * decoded in place. */ #ifndef SLAP_ZONE_ALLOC - ch_free(data.data); + ch_free(eh.bv.bv_val); #endif } #ifdef SLAP_ZONE_ALLOC - ch_free(data.data); + ch_free(eh.bv.bv_val); #endif return rc; diff --git a/servers/slapd/back-bdb/tools.c b/servers/slapd/back-bdb/tools.c index 9c6e23ef7c..604471c57a 100644 --- a/servers/slapd/back-bdb/tools.c +++ b/servers/slapd/back-bdb/tools.c @@ -18,6 +18,7 @@ #include #include +#include #define AVL_INTERNAL #include "back-bdb.h" @@ -25,6 +26,8 @@ static DBC *cursor = NULL; static DBT key, data; +static EntryHeader eh; +static int eoff; typedef struct dn_id { ID id; @@ -82,7 +85,7 @@ int bdb_tool_entry_open( DBTzero( &key ); DBTzero( &data ); key.flags = DB_DBT_REALLOC; - data.flags = DB_DBT_REALLOC; + data.flags = DB_DBT_USERMEM; if (cursor == NULL) { int rc = bdb->bi_id2entry->bdi_db->cursor( @@ -132,9 +135,9 @@ int bdb_tool_entry_close( ch_free( key.data ); key.data = NULL; } - if( data.data ) { - ch_free( data.data ); - data.data = NULL; + if( eh.bv.bv_val ) { + ch_free( eh.bv.bv_val ); + eh.bv.bv_val = NULL; } if( cursor ) { @@ -165,14 +168,19 @@ ID bdb_tool_entry_next( int rc; ID id; struct bdb_info *bdb = (struct bdb_info *) be->be_private; + char buf[16], *dptr; assert( be != NULL ); assert( slapMode & SLAP_TOOL_MODE ); assert( bdb != NULL ); + /* Get the header */ + data.ulen = data.dlen = sizeof( buf ); + data.data = buf; + data.flags |= DB_DBT_PARTIAL; rc = cursor->c_get( cursor, &key, &data, DB_NEXT ); - if( rc != 0 ) { + if( rc ) { /* If we're doing linear indexing and there are more attrs to * index, and we're at the end of the database, start over. */ @@ -190,7 +198,13 @@ ID bdb_tool_entry_next( } } - if( data.data == NULL ) { + dptr = eh.bv.bv_val; + eh.bv.bv_val = buf; + eh.bv.bv_len = data.size; + rc = entry_header( &eh ); + eoff = eh.data - eh.bv.bv_val; + eh.bv.bv_val = dptr; + if( rc ) { return NOID; } @@ -248,48 +262,64 @@ int bdb_tool_id2entry_get( Entry* bdb_tool_entry_get( BackendDB *be, ID id ) { - int rc; + int rc, off; Entry *e = NULL; - struct berval bv; + char *dptr; assert( be != NULL ); assert( slapMode & SLAP_TOOL_MODE ); - assert( data.data != NULL ); - DBT2bv( &data, &bv ); + /* Get the size */ + data.flags ^= DB_DBT_PARTIAL; + data.ulen = 0; + rc = cursor->c_get( cursor, &key, &data, DB_CURRENT ); + if ( rc != ENOMEM ) goto leave; + + /* Allocate a block and retrieve the data */ + eh.bv.bv_len = eh.nvals * sizeof( struct berval ) + data.size; + eh.bv.bv_val = ch_realloc( eh.bv.bv_val, eh.bv.bv_len ); + eh.data = eh.bv.bv_val + eh.nvals * sizeof( struct berval ); + data.data = eh.data; + data.ulen = data.size; + + /* Skip past already parsed nattr/nvals */ + eh.data += eoff; + + rc = cursor->c_get( cursor, &key, &data, DB_CURRENT ); #ifdef SLAP_ZONE_ALLOC /* FIXME: will add ctx later */ - rc = entry_decode( &bv, &e, NULL ); + rc = entry_decode( &eh, &e, NULL ); #else - rc = entry_decode( &bv, &e ); + rc = entry_decode( &eh, &e ); #endif if( rc == LDAP_SUCCESS ) { e->e_id = id; - } #ifdef BDB_HIER - if ( slapMode & SLAP_TOOL_READONLY ) { - EntryInfo *ei = NULL; - Operation op = {0}; - Opheader ohdr = {0}; - - op.o_hdr = &ohdr; - op.o_bd = be; - op.o_tmpmemctx = NULL; - op.o_tmpmfuncs = &ch_mfuncs; - - rc = bdb_cache_find_parent( &op, NULL, cursor->locker, id, &ei ); - if ( rc == LDAP_SUCCESS ) { - bdb_cache_entryinfo_unlock( ei ); - e->e_private = ei; - ei->bei_e = e; - bdb_fix_dn( e, 0 ); - ei->bei_e = NULL; - e->e_private = NULL; + if ( slapMode & SLAP_TOOL_READONLY ) { + EntryInfo *ei = NULL; + Operation op = {0}; + Opheader ohdr = {0}; + + op.o_hdr = &ohdr; + op.o_bd = be; + op.o_tmpmemctx = NULL; + op.o_tmpmfuncs = &ch_mfuncs; + + rc = bdb_cache_find_parent( &op, NULL, cursor->locker, id, &ei ); + if ( rc == LDAP_SUCCESS ) { + bdb_cache_entryinfo_unlock( ei ); + e->e_private = ei; + ei->bei_e = e; + bdb_fix_dn( e, 0 ); + ei->bei_e = NULL; + e->e_private = NULL; + } } - } #endif + } +leave: return e; } diff --git a/servers/slapd/entry.c b/servers/slapd/entry.c index f7a1fb7b8d..823d3fbd17 100644 --- a/servers/slapd/entry.c +++ b/servers/slapd/entry.c @@ -456,10 +456,6 @@ entry_clean( Entry *e ) free( e->e_bv.bv_val ); } - if ( &e->e_abv ) { - free( e->e_abv ); - } - /* free attributes */ attrs_free( e->e_attrs ); @@ -720,20 +716,39 @@ int entry_encode(Entry *e, struct berval *bv) } /* Retrieve an Entry that was stored using entry_encode above. - * We malloc a single block with the size stored above for the Entry - * and all of its Attributes. We also must lookup the stored - * attribute names to get AttributeDescriptions. To detect if the - * attributes of an Entry are later modified, we note that e->e_attr - * is always a constant offset from (e). + * First entry_header must be called to decode the size of the entry. + * Then a single block of memory must be malloc'd to accomodate the + * bervals and the bulk data. Next the bulk data is retrieved from + * the DB and parsed by entry_decode. * * Note: everything is stored in a single contiguous block, so * you can not free individual attributes or names from this * structure. Attempting to do so will likely corrupt memory. */ +int entry_header(EntryHeader *eh) +{ + unsigned char *ptr = (unsigned char *)eh->bv.bv_val; + + eh->nattrs = entry_getlen(&ptr); + if ( !eh->nattrs ) { + Debug( LDAP_DEBUG_ANY, + "entry_header: attribute count was zero\n", 0, 0, 0); + return LDAP_OTHER; + } + eh->nvals = entry_getlen(&ptr); + if ( !eh->nvals ) { + Debug( LDAP_DEBUG_ANY, + "entry_header: value count was zero\n", 0, 0, 0); + return LDAP_OTHER; + } + eh->data = (char *)ptr; + return LDAP_SUCCESS; +} + #ifdef SLAP_ZONE_ALLOC -int entry_decode(struct berval *bv, Entry **e, void *ctx) +int entry_decode(EntryHeader *eh, Entry **e, void *ctx) #else -int entry_decode(struct berval *bv, Entry **e) +int entry_decode(EntryHeader *eh, Entry **e) #endif { int i, j, count, nattrs, nvals; @@ -742,24 +757,14 @@ int entry_decode(struct berval *bv, Entry **e) Entry *x; const char *text; AttributeDescription *ad; - unsigned char *ptr = (unsigned char *)bv->bv_val; + unsigned char *ptr = (unsigned char *)eh->bv.bv_val; BerVarray bptr; - nattrs = entry_getlen(&ptr); - if (!nattrs) { - Debug( LDAP_DEBUG_ANY, - "entry_decode: attribute count was zero\n", 0, 0, 0); - return LDAP_OTHER; - } - nvals = entry_getlen(&ptr); - if (!nvals) { - Debug( LDAP_DEBUG_ANY, - "entry_decode: value count was zero\n", 0, 0, 0); - return LDAP_OTHER; - } + nattrs = eh->nattrs; + nvals = eh->nvals; x = entry_alloc(); x->e_attrs = attrs_alloc( nattrs ); - x->e_abv = ch_malloc( nvals * sizeof( struct berval )); + ptr = (unsigned char *)eh->data; i = entry_getlen(&ptr); x->e_name.bv_val = (char *) ptr; x->e_name.bv_len = i; @@ -771,10 +776,10 @@ int entry_decode(struct berval *bv, Entry **e) Debug( LDAP_DEBUG_TRACE, "entry_decode: \"%s\"\n", x->e_dn, 0, 0 ); - x->e_bv = *bv; + x->e_bv = eh->bv; a = x->e_attrs; - bptr = x->e_abv; + bptr = (BerVarray)eh->bv.bv_val; while ((i = entry_getlen(&ptr))) { struct berval bv; @@ -853,9 +858,6 @@ Entry *entry_dup( Entry *e ) ber_dupbv( &ret->e_nname, &e->e_nname ); ret->e_attrs = attrs_dup( e->e_attrs ); ret->e_ocflags = e->e_ocflags; - ret->e_bv.bv_val = NULL; - ret->e_bv.bv_len = 0; - ret->e_private = NULL; return ret; } diff --git a/servers/slapd/proto-slap.h b/servers/slapd/proto-slap.h index 05ea1defb7..61b2320e41 100644 --- a/servers/slapd/proto-slap.h +++ b/servers/slapd/proto-slap.h @@ -853,12 +853,13 @@ LDAP_SLAPD_F (ber_len_t) entry_flatsize LDAP_P(( Entry *e, int norm )); LDAP_SLAPD_F (void) entry_partsize LDAP_P(( Entry *e, ber_len_t *len, int *nattrs, int *nvals, int norm )); +LDAP_SLAPD_F (int) entry_header LDAP_P(( EntryHeader *eh )); #ifdef SLAP_ZONE_ALLOC LDAP_SLAPD_F (int) entry_decode LDAP_P(( - struct berval *bv, Entry **e, void *ctx )); + EntryHeader *eh, Entry **e, void *ctx )); #else LDAP_SLAPD_F (int) entry_decode LDAP_P(( - struct berval *bv, Entry **e )); + EntryHeader *eh, Entry **e )); #endif LDAP_SLAPD_F (int) entry_encode LDAP_P(( Entry *e, struct berval *bv )); diff --git a/servers/slapd/slap.h b/servers/slapd/slap.h index 0f132522d6..1d25e3bcfd 100644 --- a/servers/slapd/slap.h +++ b/servers/slapd/slap.h @@ -1108,6 +1108,13 @@ typedef struct slap_attr { typedef unsigned long ID; #define NOID ((ID)~0) +typedef struct slap_entry_header { + struct berval bv; + char *data; + int nattrs; + int nvals; +} EntryHeader; + /* * represents an entry in core */ @@ -1131,7 +1138,6 @@ typedef struct slap_entry { slap_mask_t e_ocflags; struct berval e_bv; /* For entry_encode/entry_decode */ - struct berval *e_abv; /* for use by the backend for any purpose */ void* e_private; -- 2.39.5