/* * __wt_block_checkpoint_unload -- * Unload a checkpoint. */ int __wt_block_checkpoint_unload( WT_SESSION_IMPL *session, WT_BLOCK *block, bool checkpoint) { WT_DECL_RET; /* Verify cleanup. */ if (block->verify) WT_TRET(__wt_verify_ckpt_unload(session, block)); /* * If it's the live system, truncate to discard any extended blocks and * discard the active extent lists. Hold the lock even though we're * unloading the live checkpoint, there could be readers active in other * checkpoints. */ if (!checkpoint) { WT_TRET(__wt_block_truncate(session, block, block->size)); __wt_spin_lock(session, &block->live_lock); __wt_block_ckpt_destroy(session, &block->live); #ifdef HAVE_DIAGNOSTIC block->live_open = false; #endif __wt_spin_unlock(session, &block->live_lock); } return (ret); }
/* * __wt_block_checkpoint_unload -- * Unload a checkpoint. */ int __wt_block_checkpoint_unload( WT_SESSION_IMPL *session, WT_BLOCK *block, bool checkpoint) { WT_DECL_RET; /* Verify cleanup. */ if (block->verify) WT_TRET(__wt_verify_ckpt_unload(session, block)); /* * If it's the live system, truncate to discard any extended blocks and * discard the active extent lists. Hold the lock even though we're * unloading the live checkpoint, there could be readers active in * other checkpoints. */ if (!checkpoint) { /* * The truncate might fail if there's a file mapping (if there's * an open checkpoint on the file), that's OK. */ WT_TRET_BUSY_OK( __wt_block_truncate(session, block->fh, block->fh->size)); __wt_spin_lock(session, &block->live_lock); __wt_block_ckpt_destroy(session, &block->live); __wt_spin_unlock(session, &block->live_lock); } return (ret); }
/* * __wt_block_salvage_start -- * Start a file salvage. */ int __wt_block_salvage_start(WT_SESSION_IMPL *session, WT_BLOCK *block) { wt_off_t len; uint32_t allocsize; allocsize = block->allocsize; /* Reset the description information in the first block. */ WT_RET(__wt_desc_write(session, block->fh, allocsize)); /* * Salvage creates a new checkpoint when it's finished, set up for * rolling an empty file forward. */ WT_RET(__wt_block_ckpt_init(session, &block->live, "live")); /* * Truncate the file to an allocation-size multiple of blocks (bytes * trailing the last block must be garbage, by definition). */ len = allocsize; if (block->size > allocsize) len = (block->size / allocsize) * allocsize; WT_RET(__wt_block_truncate(session, block, len)); /* * The file's first allocation-sized block is description information, * skip it when reading through the file. */ block->slvg_off = allocsize; /* * The only checkpoint extent we care about is the allocation list. * Start with the entire file on the allocation list, we'll "free" * any blocks we don't want as we process the file. */ WT_RET(__wt_block_insert_ext( session, block, &block->live.alloc, allocsize, len - allocsize)); /* Salvage performs a checkpoint but doesn't start or resolve it. */ WT_ASSERT(session, block->ckpt_state == WT_CKPT_NONE); block->ckpt_state = WT_CKPT_SALVAGE; return (0); }
/* * __wt_block_checkpoint_load -- * Load a checkpoint. */ int __wt_block_checkpoint_load(WT_SESSION_IMPL *session, WT_BLOCK *block, const uint8_t *addr, size_t addr_size, uint8_t *root_addr, size_t *root_addr_sizep, bool checkpoint) { WT_BLOCK_CKPT *ci, _ci; WT_DECL_ITEM(tmp); WT_DECL_RET; uint8_t *endp; ci = NULL; /* * Sometimes we don't find a root page (we weren't given a checkpoint, * or the checkpoint was empty). In that case we return an empty root * address, set that up now. */ *root_addr_sizep = 0; #ifdef HAVE_VERBOSE if (WT_VERBOSE_ISSET(session, WT_VERB_CHECKPOINT)) { if (addr != NULL) { WT_ERR(__wt_scr_alloc(session, 0, &tmp)); WT_ERR(__ckpt_string(session, block, addr, tmp)); } __wt_verbose(session, WT_VERB_CHECKPOINT, "%s: load-checkpoint: %s", block->name, addr == NULL ? "[Empty]" : (const char *)tmp->data); } #endif /* * There's a single checkpoint in the file that can be written, all of * the others are read-only. We use the same initialization calls for * readonly checkpoints, but the information doesn't persist. */ if (checkpoint) { ci = &_ci; WT_ERR(__wt_block_ckpt_init(session, ci, "checkpoint")); } else { /* * We depend on the btree level for locking: things will go bad * fast if we open the live system in two handles, or salvage, * truncate or verify the live/running file. */ #ifdef HAVE_DIAGNOSTIC __wt_spin_lock(session, &block->live_lock); WT_ASSERT(session, block->live_open == false); block->live_open = true; __wt_spin_unlock(session, &block->live_lock); #endif ci = &block->live; WT_ERR(__wt_block_ckpt_init(session, ci, "live")); } /* * If the checkpoint has an on-disk root page, load it. Otherwise, size * the file past the description information. */ if (addr == NULL || addr_size == 0) ci->file_size = block->allocsize; else { /* Crack the checkpoint cookie. */ WT_ERR(__wt_block_buffer_to_ckpt(session, block, addr, ci)); /* Verify sets up next. */ if (block->verify) WT_ERR(__wt_verify_ckpt_load(session, block, ci)); /* Read any root page. */ if (ci->root_offset != WT_BLOCK_INVALID_OFFSET) { endp = root_addr; WT_ERR(__wt_block_addr_to_buffer(block, &endp, ci->root_offset, ci->root_size, ci->root_checksum)); *root_addr_sizep = WT_PTRDIFF(endp, root_addr); } /* * Rolling a checkpoint forward requires the avail list, the * blocks from which we can allocate. */ if (!checkpoint) WT_ERR(__wt_block_extlist_read_avail( session, block, &ci->avail, ci->file_size)); } /* * If the checkpoint can be written, that means anything written after * the checkpoint is no longer interesting, truncate the file. Don't * bother checking the avail list for a block at the end of the file, * that was done when the checkpoint was first written (re-writing the * checkpoint might possibly make it relevant here, but it's unlikely * enough I don't bother). */ if (!checkpoint) WT_ERR(__wt_block_truncate(session, block, ci->file_size)); if (0) { err: /* * Don't call checkpoint-unload: unload does real work including * file truncation. If we fail early enough that the checkpoint * information isn't correct, bad things would happen. The only * allocated memory was in the service of verify, clean that up. */ if (block->verify) WT_TRET(__wt_verify_ckpt_unload(session, block)); } /* Checkpoints don't need the original information, discard it. */ if (checkpoint && ci != NULL) __wt_block_ckpt_destroy(session, ci); __wt_scr_free(session, &tmp); return (ret); }