[Date Prev][Date Next] [Chronological] [Thread] [Top]

Re: using cursors in LDBM back end with gdbm (ITS#450)



At 11:15 PM 2/10/00 GMT, adamson@andrew.cmu.edu wrote:
>Programs such as slapindex that step through an LDBM back end database,
>entry by entry, use the cursor variable
>
>static LDBMCursor *cursorp = NULL;
>
>in servers/slapd/back-ldbm/tools.c to keep track where they are in the
>database. This cursorp variable is passed to ldbm_firstkey() and
>ldbm_nextkey(), and those functions are expected to do their own database
>dependant method of cursoring.

In 1.2 or devel codes?   In 1.2, the code works because the
caller copies key to last before calling ldbm_nextkey().
In devel, the code appears to be broken in that back-ldbm is
assuming cursor support which LDBM doesn't provide.  The
solution here is to either have back-ldbm manage a last key
or have LDBM manage the last key as a "cursor".  The cursor
approach would be better as it makes LDBM job is to deal
with differnet capabilities of the underlying database engine.

A patch to fix this would be quite welcomed.  See
http://www.openldap.org/devel/contributing.html for details.

>Those firstkey and nextkey functions appear in libraries/libldbm/ldbm.c,
>once for each type of database (dbm, ndbm, gdbm, etc). The gdbm (and dbm)
>version of ldbm_firstkey() and ldbm_lastkey() do not make use of the
>cursor variable! Instead, the "key" variable is passed to the 
>gdbm_nextkey() function as the cursor, and that "key" variable is
>just a local variable in the calling function, so it has junk in it from
>the stack. The result is that the value returned by gdbm_nextkey() is
>indeterminant, (but most likely a "not found" value).
>
>ldbm_firstkey() and ldbm_lastkey() need to do the ugly task of copying
>fetched values into the cursor. The data fetched will most likely be
>free'd before the next call to ldbm_nextkey(), so a complete copy must be
>made.
>
>Here is the reimplementation of those too functions that I wrote and am
>using. They are for gdbm, and similar versions could be made for dbm.
>(As you can probably guess, I'm not real clear on this whole CVS checkin
>thang).
>
>-Mark Adamson
> Carnegie Mellon University
>
>
>
>libraries/libldbm/ldbm.c
>circa line 523 in version 1.36
>
>
>Datum
>ldbm_firstkey( LDBM ldbm, LDBMCursor **dbcp )
>{
>	Datum d, *cur;
>
>	LDBM_LOCK;
>	d = gdbm_firstkey( ldbm );
>	LDBM_UNLOCK;
>
>	/* Store the first key in the cursor */
>	if (*dbcp) free (*dbcp);
>	cur = (Datum *)malloc(sizeof(Datum));
>	if (cur) {
>		cur->dsize = d.dsize;
>		if (cur->dsize) {
>			cur->dptr = (char *)malloc(cur->dsize);
>			if (cur->dptr)
>				memcpy(cur->dptr, d.dptr, cur->dsize);
>			else {
>				free(cur);
>				cur = NULL;
>			}
>		}
>		else
>			cur->dptr = NULL;
>	}
>	*dbcp = (LDBMCursor *)cur;
>
>
>	return d;
>}
>
>Datum
>ldbm_nextkey( LDBM ldbm, Datum key, LDBMCursor *dbcp )
>{
>	Datum *cur;
>
>	/* Load the cursor into the key */
>	cur = (Datum *)dbcp;
>	if (cur == NULL) {
>		key.dptr = 0;
>		key.dsize = 0;
>		return key;
>	}
>	key.dptr = cur->dptr;
>	key.dsize = cur->dsize;
>
>	LDBM_LOCK;
>	key = gdbm_nextkey( ldbm, key );
>	LDBM_UNLOCK;
>
>	/* Save this datum back into the key */
>	if (cur->dsize == key.dsize)   /* Reuse the same dptr space */
>		memcpy(cur->dptr, key.dptr, cur->dsize);
>	else {
>		cur->dsize = key.dsize;
>		cur->dptr = (char *)realloc(cur->dptr, cur->dsize);
>		if (cur->dsize) {
>			if (cur->dptr) memcpy(cur->dptr, key.dptr,
>cur->dsize);
>			else cur->dsize = 0;
>		}
>		else
>			cur->dptr = NULL;
>	}
>	return key;
>}
>
>
>