/* * __ckpt_last_addr -- * Return the cookie associated with the file's last checkpoint. */ static int __ckpt_last_addr( WT_SESSION_IMPL *session, const char *config, WT_ITEM *addr) { WT_CONFIG ckptconf; WT_CONFIG_ITEM a, k, v; int64_t found; WT_RET(__wt_config_getones(session, config, "checkpoint", &v)); WT_RET(__wt_config_subinit(session, &ckptconf, &v)); for (found = 0; __wt_config_next(&ckptconf, &k, &v) == 0;) { /* Ignore checkpoints before the ones we've already seen. */ WT_RET(__wt_config_subgets(session, &v, "order", &a)); if (found && a.val < found) continue; found = a.val; /* * Copy out the address; our caller wants the raw cookie, not * the hex. */ WT_RET(__wt_config_subgets(session, &v, "addr", &a)); if (a.len != 0) WT_RET(__wt_nhex_to_raw(session, a.str, a.len, addr)); } return (found ? 0 : WT_NOTFOUND); }
/* * __snap_get_last -- * Return the cookie associated with the file's last snapshot. */ static int __snap_get_last( WT_SESSION_IMPL *session, const char *config, WT_ITEM *addr) { WT_CONFIG snapconf; WT_CONFIG_ITEM a, k, v; int64_t found; WT_RET(__wt_config_getones(session, config, "snapshot", &v)); WT_RET(__wt_config_subinit(session, &snapconf, &v)); for (found = 0; __wt_config_next(&snapconf, &k, &v) == 0;) { if (found) { WT_RET(__wt_config_subgets(session, &v, "order", &a)); if (a.val < found) continue; } WT_RET(__wt_config_subgets(session, &v, "addr", &a)); if (a.len == 0) WT_RET(EINVAL); /* Our caller wants the raw cookie, not the hex. */ WT_RET(__wt_nhex_to_raw(session, a.str, a.len, addr)); WT_RET(__wt_config_subgets(session, &v, "order", &a)); found = a.val; } return (found ? 0 : WT_NOTFOUND); }
/* * __ckpt_load -- * Load a single checkpoint's information into a WT_CKPT structure. */ static int __ckpt_load(WT_SESSION_IMPL *session, WT_CONFIG_ITEM *k, WT_CONFIG_ITEM *v, WT_CKPT *ckpt) { WT_CONFIG_ITEM a; char timebuf[64]; /* * Copy the name, address (raw and hex), order and time into the slot. * If there's no address, it's a fake. */ WT_RET(__wt_strndup(session, k->str, k->len, &ckpt->name)); WT_RET(__wt_config_subgets(session, v, "addr", &a)); WT_RET(__wt_buf_set(session, &ckpt->addr, a.str, a.len)); if (a.len == 0) F_SET(ckpt, WT_CKPT_FAKE); else WT_RET(__wt_nhex_to_raw(session, a.str, a.len, &ckpt->raw)); WT_RET(__wt_config_subgets(session, v, "order", &a)); if (a.len == 0) goto format; ckpt->order = a.val; WT_RET(__wt_config_subgets(session, v, "time", &a)); if (a.len == 0 || a.len > sizeof(timebuf) - 1) goto format; memcpy(timebuf, a.str, a.len); timebuf[a.len] = '\0'; if (sscanf(timebuf, "%" SCNuMAX, &ckpt->sec) != 1) goto format; WT_RET(__wt_config_subgets(session, v, "size", &a)); ckpt->ckpt_size = (uint64_t)a.val; WT_RET(__wt_config_subgets(session, v, "write_gen", &a)); if (a.len == 0) goto format; /* * The largest value a WT_CONFIG_ITEM can handle is signed: this value * appears on disk and I don't want to sign it there, so I'm casting it * here instead. */ ckpt->write_gen = (uint64_t)a.val; return (0); format: WT_RET_MSG(session, WT_ERROR, "corrupted checkpoint list"); }
/* * __snap_get_name -- * Return the cookie associated with a file's named snapshot. */ static int __snap_get_name(WT_SESSION_IMPL *session, const char *name, const char *config, WT_ITEM *addr) { WT_CONFIG snapconf; WT_CONFIG_ITEM a, k, v; WT_RET(__wt_config_getones(session, config, "snapshot", &v)); WT_RET(__wt_config_subinit(session, &snapconf, &v)); while (__wt_config_next(&snapconf, &k, &v) == 0) if (strlen(name) == k.len && strncmp(name, k.str, k.len) == 0) { WT_RET(__wt_config_subgets(session, &v, "addr", &a)); WT_RET(__wt_nhex_to_raw(session, a.str, a.len, addr)); return (0); } return (WT_NOTFOUND); }
/* * __ckpt_named_addr -- * Return the cookie associated with a file's named checkpoint. */ static int __ckpt_named_addr(WT_SESSION_IMPL *session, const char *checkpoint, const char *config, WT_ITEM *addr) { WT_CONFIG ckptconf; WT_CONFIG_ITEM a, k, v; WT_RET(__wt_config_getones(session, config, "checkpoint", &v)); WT_RET(__wt_config_subinit(session, &ckptconf, &v)); /* * Take the first match: there should never be more than a single * checkpoint of any name. */ while (__wt_config_next(&ckptconf, &k, &v) == 0) if (WT_STRING_MATCH(checkpoint, k.str, k.len)) { WT_RET(__wt_config_subgets(session, &v, "addr", &a)); if (a.len != 0) WT_RET(__wt_nhex_to_raw( session, a.str, a.len, addr)); return (0); } return (WT_NOTFOUND); }
int __wt_hex_to_raw(WT_SESSION_IMPL *session, const char *from, WT_ITEM *to) { return (__wt_nhex_to_raw(session, from, strlen(from), to)); }
/* * __wt_meta_ckptlist_get -- * Load all available checkpoint information for a file. */ int __wt_meta_ckptlist_get( WT_SESSION_IMPL *session, const char *fname, WT_CKPT **ckptbasep) { WT_CKPT *ckpt, *ckptbase; WT_CONFIG ckptconf; WT_CONFIG_ITEM a, k, v; WT_DECL_RET; WT_ITEM *buf; size_t allocated, slot; const char *config; char timebuf[64]; *ckptbasep = NULL; buf = NULL; ckptbase = NULL; allocated = slot = 0; config = NULL; /* Retrieve the metadata information for the file. */ WT_RET(__wt_metadata_read(session, fname, &config)); /* Load any existing checkpoints into the array. */ WT_ERR(__wt_scr_alloc(session, 0, &buf)); if (__wt_config_getones(session, config, "checkpoint", &v) == 0 && __wt_config_subinit(session, &ckptconf, &v) == 0) for (; __wt_config_next(&ckptconf, &k, &v) == 0; ++slot) { if (slot * sizeof(WT_CKPT) == allocated) WT_ERR(__wt_realloc(session, &allocated, (slot + 50) * sizeof(WT_CKPT), &ckptbase)); ckpt = &ckptbase[slot]; /* * Copy the name, address (raw and hex), order and time * into the slot. If there's no address, it's a fake. */ WT_ERR( __wt_strndup(session, k.str, k.len, &ckpt->name)); WT_ERR(__wt_config_subgets(session, &v, "addr", &a)); WT_ERR( __wt_buf_set(session, &ckpt->addr, a.str, a.len)); if (a.len == 0) F_SET(ckpt, WT_CKPT_FAKE); else WT_ERR(__wt_nhex_to_raw( session, a.str, a.len, &ckpt->raw)); WT_ERR(__wt_config_subgets(session, &v, "order", &a)); if (a.val == 0) goto format; ckpt->order = a.val; WT_ERR(__wt_config_subgets(session, &v, "time", &a)); if (a.len == 0) goto format; if (a.len > sizeof(timebuf) - 1) goto format; memcpy(timebuf, a.str, a.len); timebuf[a.len] = '\0'; if (sscanf(timebuf, "%" SCNuMAX, &ckpt->sec) != 1) goto format; WT_ERR(__wt_config_subgets(session, &v, "size", &a)); ckpt->ckpt_size = (uint64_t)a.val; } /* * Allocate an extra slot for a new value, plus a slot to mark the end. * * This isn't very clean, but there's necessary cooperation between the * schema layer (that maintains the list of checkpoints), the btree * layer (that knows when the root page is written, creating a new * checkpoint), and the block manager (which actually creates the * checkpoint). All of that cooperation is handled in the WT_CKPT * structure referenced from the WT_BTREE structure. */ if ((slot + 2) * sizeof(WT_CKPT) > allocated) WT_ERR(__wt_realloc(session, &allocated, (slot + 2) * sizeof(WT_CKPT), &ckptbase)); /* Sort in creation-order. */ qsort(ckptbase, slot, sizeof(WT_CKPT), __ckpt_compare_order); /* Return the array to our caller. */ *ckptbasep = ckptbase; if (0) { format: WT_ERR_MSG(session, WT_ERROR, "corrupted checkpoint list"); err: __wt_meta_ckptlist_free(session, ckptbase); } __wt_free(session, config); __wt_scr_free(&buf); return (ret); }