summaryrefslogtreecommitdiff
path: root/src/third_party/wiredtiger/src/block/block_slvg.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/third_party/wiredtiger/src/block/block_slvg.c')
-rw-r--r--src/third_party/wiredtiger/src/block/block_slvg.c190
1 files changed, 190 insertions, 0 deletions
diff --git a/src/third_party/wiredtiger/src/block/block_slvg.c b/src/third_party/wiredtiger/src/block/block_slvg.c
new file mode 100644
index 00000000000..349daa620f5
--- /dev/null
+++ b/src/third_party/wiredtiger/src/block/block_slvg.c
@@ -0,0 +1,190 @@
+/*-
+ * Copyright (c) 2008-2014 WiredTiger, Inc.
+ * All rights reserved.
+ *
+ * See the file LICENSE for redistribution information.
+ */
+
+#include "wt_internal.h"
+
+/*
+ * __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_init(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).
+ */
+ if (block->fh->size > allocsize) {
+ len = (block->fh->size / allocsize) * allocsize;
+ if (len != block->fh->size)
+ WT_RET(__wt_ftruncate(session, block->fh, len));
+ } else
+ len = allocsize;
+ block->live.file_size = 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->live.alloc, allocsize, len - allocsize));
+
+ return (0);
+}
+
+/*
+ * __wt_block_salvage_end --
+ * End a file salvage.
+ */
+int
+__wt_block_salvage_end(WT_SESSION_IMPL *session, WT_BLOCK *block)
+{
+ /* Discard the checkpoint. */
+ return (__wt_block_checkpoint_unload(session, block, 0));
+}
+
+/*
+ * __wt_block_offset_invalid --
+ * Return if the block offset is insane.
+ */
+int
+__wt_block_offset_invalid(WT_BLOCK *block, wt_off_t offset, uint32_t size)
+{
+ if (size == 0) /* < minimum page size */
+ return (1);
+ if (size % block->allocsize != 0) /* not allocation-size units */
+ return (1);
+ if (size > WT_BTREE_PAGE_SIZE_MAX) /* > maximum page size */
+ return (1);
+ /* past end-of-file */
+ if (offset + (wt_off_t)size > block->fh->size)
+ return (1);
+ return (0);
+}
+
+/*
+ * __wt_block_salvage_next --
+ * Return the address for the next potential block from the file.
+ */
+int
+__wt_block_salvage_next(WT_SESSION_IMPL *session,
+ WT_BLOCK *block, uint8_t *addr, size_t *addr_sizep, int *eofp)
+{
+ WT_BLOCK_HEADER *blk;
+ WT_DECL_ITEM(tmp);
+ WT_DECL_RET;
+ WT_FH *fh;
+ wt_off_t max, offset;
+ uint32_t allocsize, cksum, size;
+ uint8_t *endp;
+
+ *eofp = 0;
+
+ fh = block->fh;
+ allocsize = block->allocsize;
+ WT_ERR(__wt_scr_alloc(session, allocsize, &tmp));
+
+ /* Read through the file, looking for pages. */
+ for (max = fh->size;;) {
+ offset = block->slvg_off;
+ if (offset >= max) { /* Check eof. */
+ *eofp = 1;
+ goto done;
+ }
+
+ /*
+ * Read the start of a possible page (an allocation-size block),
+ * and get a page length from it. Move to the next allocation
+ * sized boundary, we'll never consider this one again.
+ */
+ WT_ERR(__wt_read(
+ session, fh, offset, (size_t)allocsize, tmp->mem));
+ blk = WT_BLOCK_HEADER_REF(tmp->mem);
+ size = blk->disk_size;
+ cksum = blk->cksum;
+
+ /*
+ * Check the block size: if it's not insane, read the block.
+ * Reading the block validates any checksum; if reading the
+ * block succeeds, return its address as a possible page,
+ * otherwise, move past it.
+ */
+ if (!__wt_block_offset_invalid(block, offset, size) &&
+ __wt_block_read_off(
+ session, block, tmp, offset, size, cksum) == 0)
+ break;
+
+ /* Free the allocation-size block. */
+ WT_ERR(__wt_verbose(session, WT_VERB_SALVAGE,
+ "skipping %" PRIu32 "B at file offset %" PRIuMAX,
+ allocsize, (uintmax_t)offset));
+ WT_ERR(__wt_block_off_free(
+ session, block, offset, (wt_off_t)allocsize));
+ block->slvg_off += allocsize;
+ }
+
+ /* Re-create the address cookie that should reference this block. */
+ endp = addr;
+ WT_ERR(__wt_block_addr_to_buffer(block, &endp, offset, size, cksum));
+ *addr_sizep = WT_PTRDIFF(endp, addr);
+
+done:
+err: __wt_scr_free(&tmp);
+ return (ret);
+}
+
+/*
+ * __wt_block_salvage_valid --
+ * Let salvage know if a block is valid.
+ */
+int
+__wt_block_salvage_valid(WT_SESSION_IMPL *session,
+ WT_BLOCK *block, uint8_t *addr, size_t addr_size, int valid)
+{
+ wt_off_t offset;
+ uint32_t size, cksum;
+
+ WT_UNUSED(session);
+ WT_UNUSED(addr_size);
+
+ /*
+ * Crack the cookie.
+ * If the upper layer took the block, move past it; if the upper layer
+ * rejected the block, move past an allocation size chunk and free it.
+ */
+ WT_RET(__wt_block_buffer_to_addr(block, addr, &offset, &size, &cksum));
+ if (valid)
+ block->slvg_off = offset + size;
+ else {
+ WT_RET(__wt_block_off_free(
+ session, block, offset, (wt_off_t)block->allocsize));
+ block->slvg_off = offset + block->allocsize;
+ }
+
+ return (0);
+}