Use a single malloc for entry_decode instead of two - partially decode

the entry to get nvals first, so the size can be computed.
This commit is contained in:
Howard Chu 2006-09-20 02:43:47 +00:00
parent cbc238721a
commit f63f46f0b1
5 changed files with 141 additions and 72 deletions

View File

@ -18,6 +18,7 @@
#include <stdio.h> #include <stdio.h>
#include <ac/string.h> #include <ac/string.h>
#include <ac/errno.h>
#include "back-bdb.h" #include "back-bdb.h"
@ -100,8 +101,9 @@ int bdb_id2entry(
DB *db = bdb->bi_id2entry->bdi_db; DB *db = bdb->bi_id2entry->bdi_db;
DBT key, data; DBT key, data;
DBC *cursor; DBC *cursor;
struct berval bv; EntryHeader eh;
int rc = 0; char buf[16];
int rc = 0, off;
ID nid; ID nid;
*e = NULL; *e = NULL;
@ -112,7 +114,7 @@ int bdb_id2entry(
BDB_ID2DISK( id, &nid ); BDB_ID2DISK( id, &nid );
DBTzero( &data ); DBTzero( &data );
data.flags = DB_DBT_MALLOC; data.flags = DB_DBT_USERMEM | DB_DBT_PARTIAL;
/* fetch it */ /* fetch it */
rc = db->cursor( db, tid, &cursor, bdb->bi_db_opflags ); rc = db->cursor( db, tid, &cursor, bdb->bi_db_opflags );
@ -122,19 +124,47 @@ int bdb_id2entry(
if ( !tid && locker ) if ( !tid && locker )
cursor->locker = 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 ); 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 ); cursor->c_close( cursor );
if( rc != 0 ) { if( rc != 0 ) {
return rc; return rc;
} }
DBT2bv( &data, &bv );
#ifdef SLAP_ZONE_ALLOC #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 #else
rc = entry_decode(&bv, e); rc = entry_decode(&eh, e);
#endif #endif
if( rc == 0 ) { if( rc == 0 ) {
@ -144,11 +174,11 @@ int bdb_id2entry(
* decoded in place. * decoded in place.
*/ */
#ifndef SLAP_ZONE_ALLOC #ifndef SLAP_ZONE_ALLOC
ch_free(data.data); ch_free(eh.bv.bv_val);
#endif #endif
} }
#ifdef SLAP_ZONE_ALLOC #ifdef SLAP_ZONE_ALLOC
ch_free(data.data); ch_free(eh.bv.bv_val);
#endif #endif
return rc; return rc;

View File

@ -18,6 +18,7 @@
#include <stdio.h> #include <stdio.h>
#include <ac/string.h> #include <ac/string.h>
#include <ac/errno.h>
#define AVL_INTERNAL #define AVL_INTERNAL
#include "back-bdb.h" #include "back-bdb.h"
@ -25,6 +26,8 @@
static DBC *cursor = NULL; static DBC *cursor = NULL;
static DBT key, data; static DBT key, data;
static EntryHeader eh;
static int eoff;
typedef struct dn_id { typedef struct dn_id {
ID id; ID id;
@ -82,7 +85,7 @@ int bdb_tool_entry_open(
DBTzero( &key ); DBTzero( &key );
DBTzero( &data ); DBTzero( &data );
key.flags = DB_DBT_REALLOC; key.flags = DB_DBT_REALLOC;
data.flags = DB_DBT_REALLOC; data.flags = DB_DBT_USERMEM;
if (cursor == NULL) { if (cursor == NULL) {
int rc = bdb->bi_id2entry->bdi_db->cursor( int rc = bdb->bi_id2entry->bdi_db->cursor(
@ -132,9 +135,9 @@ int bdb_tool_entry_close(
ch_free( key.data ); ch_free( key.data );
key.data = NULL; key.data = NULL;
} }
if( data.data ) { if( eh.bv.bv_val ) {
ch_free( data.data ); ch_free( eh.bv.bv_val );
data.data = NULL; eh.bv.bv_val = NULL;
} }
if( cursor ) { if( cursor ) {
@ -165,14 +168,19 @@ ID bdb_tool_entry_next(
int rc; int rc;
ID id; ID id;
struct bdb_info *bdb = (struct bdb_info *) be->be_private; struct bdb_info *bdb = (struct bdb_info *) be->be_private;
char buf[16], *dptr;
assert( be != NULL ); assert( be != NULL );
assert( slapMode & SLAP_TOOL_MODE ); assert( slapMode & SLAP_TOOL_MODE );
assert( bdb != NULL ); 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 ); 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 /* If we're doing linear indexing and there are more attrs to
* index, and we're at the end of the database, start over. * 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; return NOID;
} }
@ -248,48 +262,64 @@ int bdb_tool_id2entry_get(
Entry* bdb_tool_entry_get( BackendDB *be, ID id ) Entry* bdb_tool_entry_get( BackendDB *be, ID id )
{ {
int rc; int rc, off;
Entry *e = NULL; Entry *e = NULL;
struct berval bv; char *dptr;
assert( be != NULL ); assert( be != NULL );
assert( slapMode & SLAP_TOOL_MODE ); 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 #ifdef SLAP_ZONE_ALLOC
/* FIXME: will add ctx later */ /* FIXME: will add ctx later */
rc = entry_decode( &bv, &e, NULL ); rc = entry_decode( &eh, &e, NULL );
#else #else
rc = entry_decode( &bv, &e ); rc = entry_decode( &eh, &e );
#endif #endif
if( rc == LDAP_SUCCESS ) { if( rc == LDAP_SUCCESS ) {
e->e_id = id; e->e_id = id;
}
#ifdef BDB_HIER #ifdef BDB_HIER
if ( slapMode & SLAP_TOOL_READONLY ) { if ( slapMode & SLAP_TOOL_READONLY ) {
EntryInfo *ei = NULL; EntryInfo *ei = NULL;
Operation op = {0}; Operation op = {0};
Opheader ohdr = {0}; Opheader ohdr = {0};
op.o_hdr = &ohdr; op.o_hdr = &ohdr;
op.o_bd = be; op.o_bd = be;
op.o_tmpmemctx = NULL; op.o_tmpmemctx = NULL;
op.o_tmpmfuncs = &ch_mfuncs; op.o_tmpmfuncs = &ch_mfuncs;
rc = bdb_cache_find_parent( &op, NULL, cursor->locker, id, &ei ); rc = bdb_cache_find_parent( &op, NULL, cursor->locker, id, &ei );
if ( rc == LDAP_SUCCESS ) { if ( rc == LDAP_SUCCESS ) {
bdb_cache_entryinfo_unlock( ei ); bdb_cache_entryinfo_unlock( ei );
e->e_private = ei; e->e_private = ei;
ei->bei_e = e; ei->bei_e = e;
bdb_fix_dn( e, 0 ); bdb_fix_dn( e, 0 );
ei->bei_e = NULL; ei->bei_e = NULL;
e->e_private = NULL; e->e_private = NULL;
}
} }
}
#endif #endif
}
leave:
return e; return e;
} }

View File

@ -456,10 +456,6 @@ entry_clean( Entry *e )
free( e->e_bv.bv_val ); free( e->e_bv.bv_val );
} }
if ( &e->e_abv ) {
free( e->e_abv );
}
/* free attributes */ /* free attributes */
attrs_free( e->e_attrs ); 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. /* Retrieve an Entry that was stored using entry_encode above.
* We malloc a single block with the size stored above for the Entry * First entry_header must be called to decode the size of the entry.
* and all of its Attributes. We also must lookup the stored * Then a single block of memory must be malloc'd to accomodate the
* attribute names to get AttributeDescriptions. To detect if the * bervals and the bulk data. Next the bulk data is retrieved from
* attributes of an Entry are later modified, we note that e->e_attr * the DB and parsed by entry_decode.
* is always a constant offset from (e).
* *
* Note: everything is stored in a single contiguous block, so * Note: everything is stored in a single contiguous block, so
* you can not free individual attributes or names from this * you can not free individual attributes or names from this
* structure. Attempting to do so will likely corrupt memory. * 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 #ifdef SLAP_ZONE_ALLOC
int entry_decode(struct berval *bv, Entry **e, void *ctx) int entry_decode(EntryHeader *eh, Entry **e, void *ctx)
#else #else
int entry_decode(struct berval *bv, Entry **e) int entry_decode(EntryHeader *eh, Entry **e)
#endif #endif
{ {
int i, j, count, nattrs, nvals; int i, j, count, nattrs, nvals;
@ -742,24 +757,14 @@ int entry_decode(struct berval *bv, Entry **e)
Entry *x; Entry *x;
const char *text; const char *text;
AttributeDescription *ad; AttributeDescription *ad;
unsigned char *ptr = (unsigned char *)bv->bv_val; unsigned char *ptr = (unsigned char *)eh->bv.bv_val;
BerVarray bptr; BerVarray bptr;
nattrs = entry_getlen(&ptr); nattrs = eh->nattrs;
if (!nattrs) { nvals = eh->nvals;
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;
}
x = entry_alloc(); x = entry_alloc();
x->e_attrs = attrs_alloc( nattrs ); x->e_attrs = attrs_alloc( nattrs );
x->e_abv = ch_malloc( nvals * sizeof( struct berval )); ptr = (unsigned char *)eh->data;
i = entry_getlen(&ptr); i = entry_getlen(&ptr);
x->e_name.bv_val = (char *) ptr; x->e_name.bv_val = (char *) ptr;
x->e_name.bv_len = i; x->e_name.bv_len = i;
@ -771,10 +776,10 @@ int entry_decode(struct berval *bv, Entry **e)
Debug( LDAP_DEBUG_TRACE, Debug( LDAP_DEBUG_TRACE,
"entry_decode: \"%s\"\n", "entry_decode: \"%s\"\n",
x->e_dn, 0, 0 ); x->e_dn, 0, 0 );
x->e_bv = *bv; x->e_bv = eh->bv;
a = x->e_attrs; a = x->e_attrs;
bptr = x->e_abv; bptr = (BerVarray)eh->bv.bv_val;
while ((i = entry_getlen(&ptr))) { while ((i = entry_getlen(&ptr))) {
struct berval bv; struct berval bv;
@ -853,9 +858,6 @@ Entry *entry_dup( Entry *e )
ber_dupbv( &ret->e_nname, &e->e_nname ); ber_dupbv( &ret->e_nname, &e->e_nname );
ret->e_attrs = attrs_dup( e->e_attrs ); ret->e_attrs = attrs_dup( e->e_attrs );
ret->e_ocflags = e->e_ocflags; ret->e_ocflags = e->e_ocflags;
ret->e_bv.bv_val = NULL;
ret->e_bv.bv_len = 0;
ret->e_private = NULL;
return ret; return ret;
} }

View File

@ -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, LDAP_SLAPD_F (void) entry_partsize LDAP_P(( Entry *e, ber_len_t *len,
int *nattrs, int *nvals, int norm )); int *nattrs, int *nvals, int norm ));
LDAP_SLAPD_F (int) entry_header LDAP_P(( EntryHeader *eh ));
#ifdef SLAP_ZONE_ALLOC #ifdef SLAP_ZONE_ALLOC
LDAP_SLAPD_F (int) entry_decode LDAP_P(( LDAP_SLAPD_F (int) entry_decode LDAP_P((
struct berval *bv, Entry **e, void *ctx )); EntryHeader *eh, Entry **e, void *ctx ));
#else #else
LDAP_SLAPD_F (int) entry_decode LDAP_P(( LDAP_SLAPD_F (int) entry_decode LDAP_P((
struct berval *bv, Entry **e )); EntryHeader *eh, Entry **e ));
#endif #endif
LDAP_SLAPD_F (int) entry_encode LDAP_P(( Entry *e, struct berval *bv )); LDAP_SLAPD_F (int) entry_encode LDAP_P(( Entry *e, struct berval *bv ));

View File

@ -1108,6 +1108,13 @@ typedef struct slap_attr {
typedef unsigned long ID; typedef unsigned long ID;
#define NOID ((ID)~0) #define NOID ((ID)~0)
typedef struct slap_entry_header {
struct berval bv;
char *data;
int nattrs;
int nvals;
} EntryHeader;
/* /*
* represents an entry in core * represents an entry in core
*/ */
@ -1131,7 +1138,6 @@ typedef struct slap_entry {
slap_mask_t e_ocflags; slap_mask_t e_ocflags;
struct berval e_bv; /* For entry_encode/entry_decode */ struct berval e_bv; /* For entry_encode/entry_decode */
struct berval *e_abv;
/* for use by the backend for any purpose */ /* for use by the backend for any purpose */
void* e_private; void* e_private;