/* * __wt_meta_snaplist_set -- * Set a file's snapshot value from the WT_SNAPSHOT list. */ int __wt_meta_snaplist_set( WT_SESSION_IMPL *session, const char *name, WT_SNAPSHOT *snapbase) { WT_DECL_RET; WT_ITEM *buf; WT_SNAPSHOT *snap; int64_t order; const char *sep; buf = NULL; WT_ERR(__wt_scr_alloc(session, 0, &buf)); order = 0; sep = ""; WT_ERR(__wt_buf_fmt(session, buf, "snapshot=(")); WT_SNAPSHOT_FOREACH(snapbase, snap) { /* Skip deleted snapshots. */ if (F_ISSET(snap, WT_SNAP_DELETE)) continue; /* * Track the largest active snapshot counter: it's not really * a generational number or an ID because we reset it to 1 if * the snapshot we're writing is the only snapshot the file has. * The problem we're solving is when two snapshots are taken * quickly, the timer may not be unique and/or we can even see * time travel on the second snapshot if we read the time * in-between nanoseconds rolling over. All we need to know * is the real snapshot order so we don't accidentally take the * wrong "last" snapshot. */ if (snap->order > order) order = snap->order; if (F_ISSET(snap, WT_SNAP_ADD | WT_SNAP_UPDATE)) { /* Convert the raw cookie to a hex string. */ WT_ERR(__wt_raw_to_hex(session, snap->raw.data, snap->raw.size, &snap->addr)); if (F_ISSET(snap, WT_SNAP_ADD)) snap->order = order + 1; } WT_ERR(__wt_buf_catfmt(session, buf, "%s%s=(addr=\"%.*s\",order=%" PRIu64 ",time=%" PRIuMAX ",size=%" PRIu64 ")", sep, snap->name, (int)snap->addr.size, (char *)snap->addr.data, snap->order, snap->sec, snap->snapshot_size)); sep = ","; } WT_ERR(__wt_buf_catfmt(session, buf, ")")); WT_ERR(__snap_set(session, name, buf->mem)); err: __wt_scr_free(&buf); return (ret); }
/* * __raw_to_dump -- * We have a buffer where the data item contains a raw value, * convert it to a printable string. */ static int __raw_to_dump( WT_SESSION_IMPL *session, WT_ITEM *from, WT_ITEM *to, int hexonly) { if (hexonly) WT_RET(__wt_raw_to_hex(session, from->data, from->size, to)); else WT_RET( __wt_raw_to_esc_hex(session, from->data, from->size, to)); return (0); }
/* * __wt_meta_ckptlist_set -- * Set a file's checkpoint value from the WT_CKPT list. */ int __wt_meta_ckptlist_set(WT_SESSION_IMPL *session, const char *fname, WT_CKPT *ckptbase, WT_LSN *ckptlsn) { WT_CKPT *ckpt; WT_DECL_ITEM(buf); WT_DECL_RET; time_t secs; int64_t maxorder; const char *sep; WT_ERR(__wt_scr_alloc(session, 0, &buf)); maxorder = 0; sep = ""; WT_ERR(__wt_buf_fmt(session, buf, "checkpoint=(")); WT_CKPT_FOREACH(ckptbase, ckpt) { /* * Each internal checkpoint name is appended with a generation * to make it a unique name. We're solving two problems: when * two checkpoints are taken quickly, the timer may not be * unique and/or we can even see time travel on the second * checkpoint if we snapshot the time in-between nanoseconds * rolling over. Second, if we reset the generational counter * when new checkpoints arrive, we could logically re-create * specific checkpoints, racing with cursors open on those * checkpoints. I can't think of any way to return incorrect * results by racing with those cursors, but it's simpler not * to worry about it. */ if (ckpt->order > maxorder) maxorder = ckpt->order; /* Skip deleted checkpoints. */ if (F_ISSET(ckpt, WT_CKPT_DELETE)) continue; if (F_ISSET(ckpt, WT_CKPT_ADD | WT_CKPT_UPDATE)) { /* * We fake checkpoints for handles in the middle of a * bulk load. If there is a checkpoint, convert the * raw cookie to a hex string. */ if (ckpt->raw.size == 0) ckpt->addr.size = 0; else WT_ERR(__wt_raw_to_hex(session, ckpt->raw.data, ckpt->raw.size, &ckpt->addr)); /* Set the order and timestamp. */ if (F_ISSET(ckpt, WT_CKPT_ADD)) ckpt->order = ++maxorder; /* * XXX * Assumes a time_t fits into a uintmax_t, which isn't * guaranteed, a time_t has to be an arithmetic type, * but not an integral type. */ WT_ERR(__wt_seconds(session, &secs)); ckpt->sec = (uintmax_t)secs; } if (strcmp(ckpt->name, WT_CHECKPOINT) == 0) WT_ERR(__wt_buf_catfmt(session, buf, "%s%s.%" PRId64 "=(addr=\"%.*s\",order=%" PRIu64 ",time=%" PRIuMAX ",size=%" PRIu64 ",write_gen=%" PRIu64 ")", sep, ckpt->name, ckpt->order, (int)ckpt->addr.size, (char *)ckpt->addr.data, ckpt->order, ckpt->sec, ckpt->ckpt_size, ckpt->write_gen)); else WT_ERR(__wt_buf_catfmt(session, buf, "%s%s=(addr=\"%.*s\",order=%" PRIu64 ",time=%" PRIuMAX ",size=%" PRIu64 ",write_gen=%" PRIu64 ")", sep, ckpt->name, (int)ckpt->addr.size, (char *)ckpt->addr.data, ckpt->order, ckpt->sec, ckpt->ckpt_size, ckpt->write_gen)); sep = ","; } WT_ERR(__wt_buf_catfmt(session, buf, ")")); if (ckptlsn != NULL) WT_ERR(__wt_buf_catfmt(session, buf, ",checkpoint_lsn=(%" PRIu32 ",%" PRIuMAX ")", ckptlsn->file, (uintmax_t)ckptlsn->offset)); WT_ERR(__ckpt_set(session, fname, buf->mem)); err: __wt_scr_free(&buf); return (ret); }