- /* we need to free up the old recovery area, then allocate a
- new one at the end of the file. Note that we cannot use
- normal allocation to allocate the new one as that might return
- us an area that is being currently used (as of the start of
- the transaction) */
- if (recovery_head != 0) {
- tdb->stats.frees++;
- ecode = add_free_record(tdb, recovery_head,
- sizeof(rec) + rec.max_len);
+ /* build the recovery data into a single blob to allow us to do a single
+ large write, which should be more efficient */
+ p = (unsigned char *)(rec + 1);
+ for (i=0;i<tdb->transaction->num_blocks;i++) {
+ tdb_off_t offset;
+ tdb_len_t length;
+ unsigned int off;
+ unsigned char buffer[PAGESIZE];
+
+ if (tdb->transaction->blocks[i] == NULL) {
+ continue;
+ }
+
+ offset = i * PAGESIZE;
+ length = PAGESIZE;
+ if (i == tdb->transaction->num_blocks-1) {
+ length = tdb->transaction->last_block_size;
+ }
+
+ if (offset >= tdb->transaction->old_map_size) {
+ continue;
+ }
+
+ if (offset + length > tdb->file->map_size) {
+ free(rec);
+ tdb_logerr(tdb, TDB_ERR_CORRUPT, TDB_LOG_ERROR,
+ "tdb_transaction_setup_recovery:"
+ " transaction data over new region"
+ " boundary");
+ return TDB_ERR_PTR(TDB_ERR_CORRUPT);
+ }
+ if (offset + length > tdb->transaction->old_map_size) {
+ /* Short read at EOF. */
+ length = tdb->transaction->old_map_size - offset;
+ }
+ ecode = methods->tread(tdb, offset, buffer, length);