if (tdb->transaction->num_blocks <= blk ||
tdb->transaction->blocks[blk] == NULL) {
/* nope, do a real read */
- if (tdb->transaction->io_methods->read(tdb, off, buf, len) != 0) {
+ if (tdb->transaction->io_methods->tread(tdb, off, buf, len)
+ != 0) {
goto fail;
}
return 0;
if (len2 + (blk * getpagesize()) > tdb->transaction->old_map_size) {
len2 = tdb->transaction->old_map_size - (blk * getpagesize());
}
- if (tdb->transaction->io_methods->read(tdb, blk * getpagesize(),
- tdb->transaction->blocks[blk],
- len2) != 0) {
+ if (tdb->transaction->io_methods->tread(tdb, blk * getpagesize(),
+ tdb->transaction->blocks[blk],
+ len2) != 0) {
tdb_logerr(tdb, TDB_ERR_OOM, TDB_DEBUG_FATAL,
"transaction_write: failed to"
" read old block: %s",
}
static void *transaction_direct(struct tdb_context *tdb, tdb_off_t off,
- size_t len, bool write)
+ size_t len, bool write_mode)
{
- /* 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_mode) {
+ 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, false);
}
static const struct tdb_methods transaction_methods = {
uint64_t invalid = TDB_RECOVERY_INVALID_MAGIC;
/* remove the recovery marker */
- if (methods->write(tdb, tdb->transaction->magic_offset,
- &invalid, sizeof(invalid)) == -1 ||
+ if (methods->twrite(tdb, tdb->transaction->magic_offset,
+ &invalid, sizeof(invalid)) == -1 ||
transaction_sync(tdb, tdb->transaction->magic_offset,
sizeof(invalid)) == -1) {
tdb_logerr(tdb, tdb->ecode, TDB_DEBUG_FATAL,
}
if (recovery_head != 0) {
- if (methods->read(tdb, recovery_head, &rec, sizeof(rec))) {
+ if (methods->tread(tdb, recovery_head, &rec, sizeof(rec))) {
tdb_logerr(tdb, tdb->ecode, TDB_DEBUG_FATAL,
"tdb_recovery_allocate:"
" failed to read recovery record");
/* write the recovery header offset and sync - we can sync without a race here
as the magic ptr in the recovery record has not been set */
tdb_convert(tdb, &recovery_head, sizeof(recovery_head));
- if (methods->write(tdb, offsetof(struct tdb_header, recovery),
- &recovery_head, sizeof(tdb_off_t)) == -1) {
+ if (methods->twrite(tdb, offsetof(struct tdb_header, recovery),
+ &recovery_head, sizeof(tdb_off_t)) == -1) {
tdb_logerr(tdb, tdb->ecode, TDB_DEBUG_FATAL,
"tdb_recovery_allocate:"
" failed to write recovery head");
/* the recovery area contains the old data, not the
new data, so we have to call the original tdb_read
method to get it */
- if (methods->read(tdb, offset,
- p + sizeof(offset) + sizeof(length),
- length) != 0) {
+ if (methods->tread(tdb, offset,
+ p + sizeof(offset) + sizeof(length),
+ length) != 0) {
free(data);
return -1;
}
tdb_convert(tdb, p, sizeof(tailer));
/* write the recovery data to the recovery area */
- if (methods->write(tdb, recovery_offset, data,
- sizeof(*rec) + recovery_size) == -1) {
+ if (methods->twrite(tdb, recovery_offset, data,
+ sizeof(*rec) + recovery_size) == -1) {
tdb_logerr(tdb, tdb->ecode, TDB_DEBUG_FATAL,
"tdb_transaction_setup_recovery:"
" failed to write recovery data");
*magic_offset = recovery_offset + offsetof(struct tdb_recovery_record,
magic);
- if (methods->write(tdb, *magic_offset, &magic, sizeof(magic)) == -1) {
+ if (methods->twrite(tdb, *magic_offset, &magic, sizeof(magic)) == -1) {
tdb_logerr(tdb, tdb->ecode, TDB_DEBUG_FATAL,
"tdb_transaction_setup_recovery:"
" failed to write recovery magic");
length = tdb->transaction->last_block_size;
}
- if (methods->write(tdb, offset, tdb->transaction->blocks[i],
- length) == -1) {
+ if (methods->twrite(tdb, offset, tdb->transaction->blocks[i],
+ length) == -1) {
tdb_logerr(tdb, tdb->ecode, TDB_DEBUG_FATAL,
"tdb_transaction_commit:"
" write failed during commit");
}
/* read the full recovery data */
- if (tdb->methods->read(tdb, recovery_head + sizeof(rec), data,
- rec.len) == -1) {
+ if (tdb->methods->tread(tdb, recovery_head + sizeof(rec), data,
+ rec.len) == -1) {
tdb_logerr(tdb, tdb->ecode, TDB_DEBUG_FATAL,
"tdb_transaction_recover:"
" failed to read recovery data");
memcpy(&len, p + sizeof(ofs), sizeof(len));
p += sizeof(ofs) + sizeof(len);
- if (tdb->methods->write(tdb, ofs, p, len) == -1) {
+ if (tdb->methods->twrite(tdb, ofs, p, len) == -1) {
free(data);
tdb_logerr(tdb, tdb->ecode, TDB_DEBUG_FATAL,
"tdb_transaction_recover:"