************************************************************************
Before now, the Berkeley DB back end was supplied the DB_DBT_MALLOC flag
and it became the caller's responsibility to handle any memory allocated
and returned by cdb_fetch() and cdb_next_item(). These heuristics are
not expected to be compatible with new back ends currently in planning.
cdb_fetch() and cdb_next_item() now return data that is to be considered
immutable (don't write to it or you'll segfault). The caller must still
call cdb_free() to free the `struct cdbdata` itself, but the pointers
inside it point to buffers that the back end will reuse.
After a call to cdb_fetch() or cdb_next_item(), the buffers are
guaranteed to be readable until the next call to one of those functions
on the same table.
struct bdb_tsd {
DB_TXN *tid; // Transaction handle
DBC *cursors[MAXCDB]; // Cursors, for traversals...
struct bdb_tsd {
DB_TXN *tid; // Transaction handle
DBC *cursors[MAXCDB]; // Cursors, for traversals...
+ DBT dbkey[MAXCDB];
+ DBT dbdata[MAXCDB];
}
struct cdbdata *tempcdb;
}
struct cdbdata *tempcdb;
int ret;
memset(&dkey, 0, sizeof(DBT));
int ret;
memset(&dkey, 0, sizeof(DBT));
dkey.data = (void *) key;
if (TSD->tid != NULL) {
dkey.data = (void *) key;
if (TSD->tid != NULL) {
- memset(&dret, 0, sizeof(DBT));
- dret.flags = DB_DBT_MALLOC;
- ret = bdb_table[cdb]->get(bdb_table[cdb], TSD->tid, &dkey, &dret, 0);
+ TSD->dbdata[cdb].flags = DB_DBT_REALLOC;
+ ret = bdb_table[cdb]->get(bdb_table[cdb], TSD->tid, &dkey, &TSD->dbdata[cdb], 0);
- memset(&dret, 0, sizeof(DBT));
- dret.flags = DB_DBT_MALLOC;
+ TSD->dbdata[cdb].flags = DB_DBT_REALLOC;
curs = bdb_localcursor(cdb);
curs = bdb_localcursor(cdb);
- ret = curs->c_get(curs, &dkey, &dret, DB_SET);
+ ret = curs->c_get(curs, &dkey, &TSD->dbdata[cdb], DB_SET);
bdb_cclose(curs);
} while (ret == DB_LOCK_DEADLOCK);
}
bdb_cclose(curs);
} while (ret == DB_LOCK_DEADLOCK);
}
- tempcdb->len = dret.size;
- tempcdb->ptr = dret.data;
+ tempcdb->len = TSD->dbdata[cdb].size;
+ tempcdb->ptr = TSD->dbdata[cdb].data;
bdb_decompress_if_necessary(tempcdb);
return (tempcdb);
}
bdb_decompress_if_necessary(tempcdb);
return (tempcdb);
}
-//
-// Note that we only free the 'ptr' portion if it is not NULL. This allows
-// other code to assume ownership of that memory simply by storing the
-// pointer elsewhere and then setting 'ptr' to NULL. bdb_free() will then
-// avoid freeing it.
void bdb_free(struct cdbdata *cdb) {
void bdb_free(struct cdbdata *cdb) {
- if (cdb->ptr) {
- free(cdb->ptr);
- }
// Fetch the next item in a sequential search. Returns a pointer to a
// cdbdata structure, or NULL if we've hit the end.
struct cdbdata *bdb_next_item(int cdb) {
// Fetch the next item in a sequential search. Returns a pointer to a
// cdbdata structure, or NULL if we've hit the end.
struct cdbdata *bdb_next_item(int cdb) {
struct cdbdata *cdbret;
int ret = 0;
struct cdbdata *cdbret;
int ret = 0;
- // Initialize the key/data pair so the flags aren't set.
- memset(&key, 0, sizeof(key));
- memset(&data, 0, sizeof(data));
- data.flags = DB_DBT_MALLOC;
+ // reuse memory from the previous call.
+ TSD->dbkey[cdb].flags = DB_DBT_MALLOC;
+ TSD->dbdata[cdb].flags = DB_DBT_MALLOC;
- ret = TSD->cursors[cdb]->c_get(TSD->cursors[cdb], &key, &data, DB_NEXT);
+ ret = TSD->cursors[cdb]->c_get(TSD->cursors[cdb], &TSD->dbkey[cdb], &TSD->dbdata[cdb], DB_NEXT);
if (ret) {
if (ret != DB_NOTFOUND) {
if (ret) {
if (ret != DB_NOTFOUND) {
}
cdbret = (struct cdbdata *) malloc(sizeof(struct cdbdata));
}
cdbret = (struct cdbdata *) malloc(sizeof(struct cdbdata));
- cdbret->len = data.size;
- cdbret->ptr = data.data;
+ cdbret->len = TSD->dbdata[cdb].size;
+ cdbret->ptr = TSD->dbdata[cdb].data;
bdb_decompress_if_necessary(cdbret);
return (cdbret);
bdb_decompress_if_necessary(cdbret);
return (cdbret);