From: Volker Lendecke Date: Mon, 19 Feb 2007 11:45:33 +0000 (+0000) Subject: r21445: Apply tdb_parse_record Tridges error return, merge to 3_0_25 and 4_0 X-Git-Tag: samba-4.0.0alpha6~801^3~3268 X-Git-Url: http://git.samba.org/samba.git/?p=sfrench%2Fsamba-autobuild%2F.git;a=commitdiff_plain;h=eaaf246d4fa42df5e590ee5bfe54e672abd26b02 r21445: Apply tdb_parse_record Tridges error return, merge to 3_0_25 and 4_0 (This used to be commit afe7d7855841066b88859976ac748cbf438a9a9f) --- diff --git a/source4/lib/tdb/common/io.c b/source4/lib/tdb/common/io.c index 5d2c5c8e2ee..b3d1c56dc4d 100644 --- a/source4/lib/tdb/common/io.c +++ b/source4/lib/tdb/common/io.c @@ -353,6 +353,40 @@ unsigned char *tdb_alloc_read(struct tdb_context *tdb, tdb_off_t offset, tdb_len return buf; } +/* Give a piece of tdb data to a parser */ + +int tdb_parse_data(struct tdb_context *tdb, TDB_DATA key, + tdb_off_t offset, tdb_len_t len, + int (*parser)(TDB_DATA key, TDB_DATA data, + void *private_data), + void *private_data) +{ + TDB_DATA data; + int result; + + data.dsize = len; + + if ((tdb->transaction == NULL) && (tdb->map_ptr != NULL)) { + /* + * Optimize by avoiding the malloc/memcpy/free, point the + * parser directly at the mmap area. + */ + if (tdb->methods->tdb_oob(tdb, offset+len, 0) != 0) { + return -1; + } + data.dptr = offset + (unsigned char *)tdb->map_ptr; + return parser(key, data, private_data); + } + + if (!(data.dptr = tdb_alloc_read(tdb, offset, len))) { + return -1; + } + + result = parser(key, data, private_data); + free(data.dptr); + return result; +} + /* read/write a record */ int tdb_rec_read(struct tdb_context *tdb, tdb_off_t offset, struct list_struct *rec) { diff --git a/source4/lib/tdb/common/tdb.c b/source4/lib/tdb/common/tdb.c index b610cb35b29..03a66804b3f 100644 --- a/source4/lib/tdb/common/tdb.c +++ b/source4/lib/tdb/common/tdb.c @@ -56,6 +56,10 @@ static void tdb_increment_seqnum(struct tdb_context *tdb) tdb_brlock(tdb, TDB_SEQNUM_OFS, F_UNLCK, F_SETLKW, 1, 1); } +static int tdb_key_compare(TDB_DATA key, TDB_DATA data, void *private_data) +{ + return memcmp(data.dptr, key.dptr, data.dsize); +} /* Returns 0 on fail. On success, return offset of record, and fills in rec */ @@ -73,19 +77,12 @@ static tdb_off_t tdb_find(struct tdb_context *tdb, TDB_DATA key, u32 hash, if (tdb_rec_read(tdb, rec_ptr, r) == -1) return 0; - if (!TDB_DEAD(r) && hash==r->full_hash && key.dsize==r->key_len) { - unsigned char *k; - /* a very likely hit - read the key */ - k = tdb_alloc_read(tdb, rec_ptr + sizeof(*r), - r->key_len); - if (!k) - return 0; - - if (memcmp(key.dptr, k, key.dsize) == 0) { - SAFE_FREE(k); - return rec_ptr; - } - SAFE_FREE(k); + if (!TDB_DEAD(r) && hash==r->full_hash + && key.dsize==r->key_len + && tdb_parse_data(tdb, key, rec_ptr + sizeof(*r), + r->key_len, tdb_key_compare, + NULL) == 0) { + return rec_ptr; } rec_ptr = r->next; } @@ -163,6 +160,47 @@ TDB_DATA tdb_fetch(struct tdb_context *tdb, TDB_DATA key) return ret; } +/* + * Find an entry in the database and hand the record's data to a parsing + * function. The parsing function is executed under the chain read lock, so it + * should be fast and should not block on other syscalls. + * + * DONT CALL OTHER TDB CALLS FROM THE PARSER, THIS MIGHT LEAD TO SEGFAULTS. + * + * For mmapped tdb's that do not have a transaction open it points the parsing + * function directly at the mmap area, it avoids the malloc/memcpy in this + * case. If a transaction is open or no mmap is available, it has to do + * malloc/read/parse/free. + * + * This is interesting for all readers of potentially large data structures in + * the tdb records, ldb indexes being one example. + */ + +int tdb_parse_record(struct tdb_context *tdb, TDB_DATA key, + int (*parser)(TDB_DATA key, TDB_DATA data, + void *private_data), + void *private_data) +{ + tdb_off_t rec_ptr; + struct list_struct rec; + int ret; + u32 hash; + + /* find which hash bucket it is in */ + hash = tdb->hash_fn(&key); + + if (!(rec_ptr = tdb_find_lock_hash(tdb,key,hash,F_RDLCK,&rec))) { + return TDB_ERRCODE(TDB_ERR_NOEXIST, 0); + } + + ret = tdb_parse_data(tdb, key, rec_ptr + sizeof(rec) + rec.key_len, + rec.data_len, parser, private_data); + + tdb_unlock(tdb, BUCKET(rec.full_hash), F_RDLCK); + + return ret; +} + /* check if an entry in the database exists note that 1 is returned if the key is found and 0 is returned if not found diff --git a/source4/lib/tdb/common/tdb_private.h b/source4/lib/tdb/common/tdb_private.h index 52778579421..a05f4da0cfd 100644 --- a/source4/lib/tdb/common/tdb_private.h +++ b/source4/lib/tdb/common/tdb_private.h @@ -196,6 +196,11 @@ int tdb_rec_read(struct tdb_context *tdb, tdb_off_t offset, struct list_struct * int tdb_rec_write(struct tdb_context *tdb, tdb_off_t offset, struct list_struct *rec); int tdb_do_delete(struct tdb_context *tdb, tdb_off_t rec_ptr, struct list_struct *rec); unsigned char *tdb_alloc_read(struct tdb_context *tdb, tdb_off_t offset, tdb_len_t len); +int tdb_parse_data(struct tdb_context *tdb, TDB_DATA key, + tdb_off_t offset, tdb_len_t len, + int (*parser)(TDB_DATA key, TDB_DATA data, + void *private_data), + void *private_data); tdb_off_t tdb_find_lock_hash(struct tdb_context *tdb, TDB_DATA key, u32 hash, int locktype, struct list_struct *rec); void tdb_io_init(struct tdb_context *tdb); diff --git a/source4/lib/tdb/include/tdb.h b/source4/lib/tdb/include/tdb.h index cbcaf9023cb..07a8160f103 100644 --- a/source4/lib/tdb/include/tdb.h +++ b/source4/lib/tdb/include/tdb.h @@ -101,6 +101,10 @@ void tdb_set_logging_function(struct tdb_context *tdb, const struct tdb_logging_ enum TDB_ERROR tdb_error(struct tdb_context *tdb); const char *tdb_errorstr(struct tdb_context *tdb); TDB_DATA tdb_fetch(struct tdb_context *tdb, TDB_DATA key); +int tdb_parse_record(struct tdb_context *tdb, TDB_DATA key, + int (*parser)(TDB_DATA key, TDB_DATA data, + void *private_data), + void *private_data); int tdb_delete(struct tdb_context *tdb, TDB_DATA key); int tdb_store(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf, int flag); int tdb_append(struct tdb_context *tdb, TDB_DATA key, TDB_DATA new_dbuf);