return 0;
}
-/* This is only neded for tdb_access_commit, but used everywhere to simplify. */
-struct tdb_access_hdr {
- tdb_off_t off;
- tdb_len_t len;
- bool convert;
-};
-
const void *tdb_access_read(struct tdb_context *tdb,
tdb_off_t off, tdb_len_t len, bool convert)
{
struct tdb_access_hdr *hdr;
hdr = _tdb_alloc_read(tdb, off, len, sizeof(*hdr));
if (hdr) {
+ hdr->next = tdb->access;
+ tdb->access = hdr;
ret = hdr + 1;
if (convert)
tdb_convert(tdb, (void *)ret, len);
struct tdb_access_hdr *hdr;
hdr = _tdb_alloc_read(tdb, off, len, sizeof(*hdr));
if (hdr) {
+ hdr->next = tdb->access;
+ tdb->access = hdr;
hdr->off = off;
hdr->len = len;
hdr->convert = convert;
return ret;
}
-bool is_direct(const struct tdb_context *tdb, const void *p)
+static struct tdb_access_hdr **find_hdr(struct tdb_context *tdb, const void *p)
{
- return (tdb->map_ptr
- && (char *)p >= (char *)tdb->map_ptr
- && (char *)p < (char *)tdb->map_ptr + tdb->map_size);
+ struct tdb_access_hdr **hp;
+
+ for (hp = &tdb->access; *hp; hp = &(*hp)->next) {
+ if (*hp + 1 == p)
+ return hp;
+ }
+ return NULL;
}
void tdb_access_release(struct tdb_context *tdb, const void *p)
{
- if (is_direct(tdb, p))
+ struct tdb_access_hdr *hdr, **hp = find_hdr(tdb, p);
+
+ if (hp) {
+ hdr = *hp;
+ *hp = hdr->next;
+ free(hdr);
+ } else
tdb->direct_access--;
- else
- free((struct tdb_access_hdr *)p - 1);
}
int tdb_access_commit(struct tdb_context *tdb, void *p)
{
+ struct tdb_access_hdr *hdr, **hp = find_hdr(tdb, p);
int ret = 0;
- if (!tdb->map_ptr
- || (char *)p < (char *)tdb->map_ptr
- || (char *)p >= (char *)tdb->map_ptr + tdb->map_size) {
- struct tdb_access_hdr *hdr;
-
- hdr = (struct tdb_access_hdr *)p - 1;
+ if (hp) {
+ hdr = *hp;
if (hdr->convert)
ret = tdb_write_convert(tdb, hdr->off, p, hdr->len);
else
ret = tdb_write(tdb, hdr->off, p, hdr->len);
+ *hp = hdr->next;
free(hdr);
} else
tdb->direct_access--;
uint32_t ltype;
};
+/* This is only needed for tdb_access_commit, but used everywhere to
+ * simplify. */
+struct tdb_access_hdr {
+ struct tdb_access_hdr *next;
+ tdb_off_t off;
+ tdb_len_t len;
+ bool convert;
+};
+
struct tdb_context {
/* Filename of the database. */
const char *name;
struct tdb_attribute_stats *stats;
+ /* Direct access information */
+ struct tdb_access_hdr *access;
+
/* Single list of all TDBs, to avoid multiple opens. */
struct tdb_context *next;
dev_t device;
void *tdb_access_write(struct tdb_context *tdb,
tdb_off_t off, tdb_len_t len, bool convert);
-/* Is this pointer direct? (Otherwise it's malloced) */
-bool is_direct(const struct tdb_context *tdb, const void *p);
-
/* Release result of tdb_access_read/write. */
void tdb_access_release(struct tdb_context *tdb, const void *p);
/* Commit result of tdb_acces_write. */
tdb->logfn = NULL;
tdb->transaction = NULL;
tdb->stats = NULL;
+ tdb->access = NULL;
tdb_hash_init(tdb);
tdb_io_init(tdb);
tdb_lock_init(tdb);
return NULL;
}
-/* FIXME: modify, don't rewrite! */
static int update_rec_hdr(struct tdb_context *tdb,
tdb_off_t off,
tdb_len_t keylen,
h.hlock_range, F_WRLCK);
return 0;
}
- /* FIXME: See if right record is free? */
} else {
if (flag == TDB_MODIFY) {
/* if the record doesn't exist and we
F_WRLCK);
return 0;
}
- /* FIXME: Check right record free? */
/* Slow path. */
newdata = malloc(key.dsize + old_dlen + dbuf.dsize);
static void *transaction_direct(struct tdb_context *tdb, tdb_off_t off,
size_t len, bool write)
{
- /* FIXME */
- return NULL;
+ size_t blk = off / getpagesize(), end_blk;
+
+ /* This is wrong for zero-length blocks, but will fail gracefully */
+ end_blk = (off + len - 1) / getpagesize();
+
+ /* Can only do direct if in single block and we've already copied. */
+ if (write) {
+ if (blk != end_blk)
+ return NULL;
+ if (blk >= tdb->transaction->num_blocks)
+ return NULL;
+ if (tdb->transaction->blocks[blk] == NULL)
+ return NULL;
+ return tdb->transaction->blocks[blk] + off % getpagesize();
+ }
+
+ /* Single which we have copied? */
+ if (blk == end_blk
+ && blk < tdb->transaction->num_blocks
+ && tdb->transaction->blocks[blk])
+ return tdb->transaction->blocks[blk] + off % getpagesize();
+
+ /* Otherwise must be all not copied. */
+ while (blk < end_blk) {
+ if (blk >= tdb->transaction->num_blocks)
+ break;
+ if (tdb->transaction->blocks[blk])
+ return NULL;
+ blk++;
+ }
+ return tdb->transaction->io_methods->direct(tdb, off, len, write);
}
static const struct tdb_methods transaction_methods = {