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 <ac/string.h>
#include <ac/errno.h>
#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;

View File

@ -18,6 +18,7 @@
#include <stdio.h>
#include <ac/string.h>
#include <ac/errno.h>
#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,26 +262,40 @@ 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;
@ -290,6 +318,8 @@ Entry* bdb_tool_entry_get( BackendDB *be, ID id )
}
}
#endif
}
leave:
return e;
}

View File

@ -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;
}

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,
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 ));

View File

@ -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;