summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVolker Lendecke <vlendec@samba.org>2007-02-19 11:45:33 +0000
committerVolker Lendecke <vlendec@samba.org>2007-02-19 11:45:33 +0000
commitbad31cdd27c54fd6189f7925251196fa19a1b6ff (patch)
tree9e18cee70f1aad0aaae8f0d622e971f740989c6f
parentcd5029eaec438ff4ddf695f060d7478c9da66495 (diff)
downloadsamba-bad31cdd27c54fd6189f7925251196fa19a1b6ff.tar.gz
samba-bad31cdd27c54fd6189f7925251196fa19a1b6ff.tar.xz
samba-bad31cdd27c54fd6189f7925251196fa19a1b6ff.zip
r21445: Apply tdb_parse_record Tridges error return, merge to 3_0_25 and 4_0
-rw-r--r--source/tdb/common/io.c34
-rw-r--r--source/tdb/common/tdb.c64
-rw-r--r--source/tdb/common/tdb_private.h5
-rw-r--r--source/tdb/include/tdb.h4
4 files changed, 94 insertions, 13 deletions
diff --git a/source/tdb/common/io.c b/source/tdb/common/io.c
index 988ce1d911e..9a8e270dcc6 100644
--- a/source/tdb/common/io.c
+++ b/source/tdb/common/io.c
@@ -355,6 +355,40 @@ char *tdb_alloc_read(struct tdb_context *tdb, tdb_off_t offset, tdb_len_t 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 + (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/source/tdb/common/tdb.c b/source/tdb/common/tdb.c
index 248acb7374e..bf4c01d1b3a 100644
--- a/source/tdb/common/tdb.c
+++ b/source/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) {
- 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/source/tdb/common/tdb_private.h b/source/tdb/common/tdb_private.h
index 56f609fb82c..7fc136c6a70 100644
--- a/source/tdb/common/tdb_private.h
+++ b/source/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);
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/source/tdb/include/tdb.h b/source/tdb/include/tdb.h
index b783f23a1ef..a0f6f983824 100644
--- a/source/tdb/include/tdb.h
+++ b/source/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);