/* * __wt_block_ckpt_to_buffer -- * Convert the components into its checkpoint cookie. */ int __wt_block_ckpt_to_buffer(WT_SESSION_IMPL *session, WT_BLOCK *block, uint8_t **pp, WT_BLOCK_CKPT *ci) { uint64_t a; if (ci->version != WT_BM_CHECKPOINT_VERSION) WT_RET_MSG(session, WT_ERROR, "unsupported checkpoint version"); (*pp)[0] = ci->version; (*pp)++; WT_RET(__wt_block_addr_to_buffer(block, pp, ci->root_offset, ci->root_size, ci->root_cksum)); WT_RET(__wt_block_addr_to_buffer(block, pp, ci->alloc.offset, ci->alloc.size, ci->alloc.cksum)); WT_RET(__wt_block_addr_to_buffer(block, pp, ci->avail.offset, ci->avail.size, ci->avail.cksum)); WT_RET(__wt_block_addr_to_buffer(block, pp, ci->discard.offset, ci->discard.size, ci->discard.cksum)); a = (uint64_t)ci->file_size; WT_RET(__wt_vpack_uint(pp, 0, a)); a = (uint64_t)ci->ckpt_size; WT_RET(__wt_vpack_uint(pp, 0, a)); return (0); }
int main(void) { uint8_t buf[10], *p, *end; int64_t i; for (i = 1; i < 1LL << 60; i <<= 1) { end = buf; testutil_check( __wt_vpack_uint(&end, sizeof(buf), (uint64_t)i)); printf("%" PRId64 " ", i); for (p = buf; p < end; p++) printf("%02x", *p); printf("\n"); end = buf; testutil_check(__wt_vpack_int(&end, sizeof(buf), -i)); printf("%" PRId64 " ", -i); for (p = buf; p < end; p++) printf("%02x", *p); printf("\n"); } return (0); }
void test_value(int64_t val) { const uint8_t *cp; uint8_t buf[10], *p; int64_t sinput, soutput; uint64_t uinput, uoutput; size_t used_len; sinput = val; p = buf; assert(__wt_vpack_int(&p, sizeof(buf), sinput) == 0); used_len = (size_t)(p - buf); cp = buf; assert(__wt_vunpack_int(&cp, used_len, &soutput) == 0); /* Ensure we got the correct value back */ if (sinput != soutput) { fprintf(stderr, "mismatch %" PRIu64 ", %" PRIu64 "\n", sinput, soutput); abort(); } /* Ensure that decoding used the correct amount of buffer */ if (cp != p) { fprintf(stderr, "Unpack consumed wrong size for %" PRId64 ", expected %" WT_SIZET_FMT ", got %" WT_SIZET_FMT "\n", sinput, used_len, cp > p ? used_len + (size_t)(cp - p) : /* More than buf used */ used_len - (size_t)(p - cp)); /* Less than buf used */ abort(); } /* Test unsigned, convert negative into bigger positive values */ uinput = (uint64_t)val; p = buf; assert(__wt_vpack_uint(&p, sizeof(buf), uinput) == 0); cp = buf; assert(__wt_vunpack_uint( &cp, sizeof(buf), &uoutput) == 0); /* Ensure we got the correct value back */ if (sinput != soutput) { fprintf(stderr, "mismatch %" PRIu64 ", %" PRIu64 "\n", sinput, soutput); abort(); } /* Ensure that decoding used the correct amount of buffer */ if (cp != p) { fprintf(stderr, "Unpack consumed wrong size for %" PRId64 ", expected %" WT_SIZET_FMT ", got %" WT_SIZET_FMT "\n", sinput, used_len, cp > p ? used_len + (size_t)(cp - p) : used_len - (size_t)(p - cp)); abort(); } }
/* * __wt_block_addr_to_buffer -- * Convert the filesystem components into its address cookie. */ int __wt_block_addr_to_buffer(WT_BLOCK *block, uint8_t **pp, wt_off_t offset, uint32_t size, uint32_t checksum) { uint64_t o, s, c; /* See the comment above: this is the reverse operation. */ if (size == 0) { o = WT_BLOCK_INVALID_OFFSET; s = c = 0; } else { o = (uint64_t)offset / block->allocsize - 1; s = size / block->allocsize; c = checksum; } WT_RET(__wt_vpack_uint(pp, 0, o)); WT_RET(__wt_vpack_uint(pp, 0, s)); WT_RET(__wt_vpack_uint(pp, 0, c)); return (0); }
int main(void) { const uint8_t *cp; uint8_t buf[10], *p; uint64_t ncalls, r, r2, s; int i; ncalls = 0; for (i = 0; i < 10000000; i++) { for (s = 0; s < 50; s += 5) { ++ncalls; r = 1ULL << s; #if 1 p = buf; assert(__wt_vpack_uint(&p, sizeof(buf), r) == 0); cp = buf; assert(__wt_vunpack_uint(&cp, sizeof(buf), &r2) == 0); #else /* * Note: use memmove for comparison because GCC does * aggressive optimization of memcpy and it's difficult * to measure anything. */ p = buf; memmove(p, &r, sizeof(r)); cp = buf; memmove(&r2, cp, sizeof(r2)); #endif if (r != r2) { fprintf(stderr, "mismatch!\n"); break; } } } printf("Number of calls: %llu\n", (unsigned long long)ncalls); return (0); }
int main() { uint8_t buf[10], *p; uint64_t r, r2, ncalls; int i, s; ncalls = 0; for (i = 0; i < 10000000; i++) { for (s = 0; s < 50; s += 5) { ++ncalls; r = 1 << s; #if 1 p = buf; __wt_vpack_uint(NULL, &p, sizeof buf, r); p = buf; __wt_vunpack_uint(NULL, &p, sizeof buf, &r2); #else /* * Note: use memmove for comparison because GCC does * aggressive optimization of memcpy and it's difficult * to measure anything. */ p = buf; memmove(p, &r, sizeof r); p = buf; memmove(&r2, p, sizeof r2); #endif if (r != r2) { fprintf(stderr, "mismatch!\n"); break; } } } printf("Number of calls: %llu\n", (unsigned long long)ncalls); return (0); }
/* * __wt_txn_checkpoint_log -- * Write a log record for a checkpoint operation. */ int __wt_txn_checkpoint_log( WT_SESSION_IMPL *session, int full, uint32_t flags, WT_LSN *lsnp) { WT_DECL_RET; WT_DECL_ITEM(logrec); WT_LSN *ckpt_lsn; WT_TXN *txn; const char *fmt = WT_UNCHECKED_STRING(IIQIU); uint8_t *end, *p; size_t recsize; uint32_t i, rectype = WT_LOGREC_CHECKPOINT; txn = &session->txn; ckpt_lsn = &txn->ckpt_lsn; /* * If this is a file sync, log it unless there is a full checkpoint in * progress. */ if (!full) { if (txn->full_ckpt) { if (lsnp != NULL) *lsnp = *ckpt_lsn; return (0); } else return (__txn_log_file_sync(session, flags, lsnp)); } switch (flags) { case WT_TXN_LOG_CKPT_PREPARE: txn->full_ckpt = 1; *ckpt_lsn = S2C(session)->log->alloc_lsn; break; case WT_TXN_LOG_CKPT_START: /* Take a copy of the transaction snapshot. */ txn->ckpt_nsnapshot = txn->snapshot_count; recsize = txn->ckpt_nsnapshot * WT_INTPACK64_MAXSIZE; WT_ERR(__wt_scr_alloc(session, recsize, &txn->ckpt_snapshot)); p = txn->ckpt_snapshot->mem; end = p + recsize; for (i = 0; i < txn->snapshot_count; i++) WT_ERR(__wt_vpack_uint( &p, WT_PTRDIFF(end, p), txn->snapshot[i])); break; case WT_TXN_LOG_CKPT_STOP: /* * During a clean connection close, we get here without the * prepare or start steps. In that case, log the current LSN * as the checkpoint LSN. */ if (!txn->full_ckpt) { txn->ckpt_nsnapshot = 0; *ckpt_lsn = S2C(session)->log->alloc_lsn; } /* Write the checkpoint log record. */ WT_ERR(__wt_struct_size(session, &recsize, fmt, rectype, ckpt_lsn->file, ckpt_lsn->offset, txn->ckpt_nsnapshot, &txn->ckpt_snapshot)); WT_ERR(__wt_logrec_alloc(session, recsize, &logrec)); WT_ERR(__wt_struct_pack(session, (uint8_t *)logrec->data + logrec->size, recsize, fmt, rectype, ckpt_lsn->file, ckpt_lsn->offset, txn->ckpt_nsnapshot, &txn->ckpt_snapshot)); logrec->size += (uint32_t)recsize; WT_ERR(__wt_log_write(session, logrec, lsnp, 0)); /* * If this full checkpoint completed successfully and there is * no hot backup in progress, tell the logging subsystem the * checkpoint LSN so that it can archive. */ if (!S2C(session)->hot_backup) WT_ERR(__wt_log_ckpt(session, ckpt_lsn)); /* FALLTHROUGH */ case WT_TXN_LOG_CKPT_FAIL: /* Cleanup any allocated resources */ INIT_LSN(ckpt_lsn); txn->ckpt_nsnapshot = 0; __wt_scr_free(&txn->ckpt_snapshot); txn->full_ckpt = 0; break; } err: __wt_logrec_free(session, &logrec); return (ret); }
/* * __wt_txn_checkpoint_log -- * Write a log record for a checkpoint operation. */ int __wt_txn_checkpoint_log( WT_SESSION_IMPL *session, bool full, uint32_t flags, WT_LSN *lsnp) { WT_CONNECTION_IMPL *conn; WT_DECL_ITEM(logrec); WT_DECL_RET; WT_ITEM *ckpt_snapshot, empty; WT_LSN *ckpt_lsn; WT_TXN *txn; WT_TXN_GLOBAL *txn_global; uint8_t *end, *p; size_t recsize; uint32_t i, rectype; const char *fmt; conn = S2C(session); txn_global = &conn->txn_global; txn = &session->txn; ckpt_lsn = &txn->ckpt_lsn; /* * If this is a file sync, log it unless there is a full checkpoint in * progress. */ if (!full) { if (txn->full_ckpt) { if (lsnp != NULL) *lsnp = *ckpt_lsn; return (0); } return (__txn_log_file_sync(session, flags, lsnp)); } switch (flags) { case WT_TXN_LOG_CKPT_PREPARE: txn->full_ckpt = true; if (conn->compat_major >= WT_LOG_V2) { /* * Write the system log record containing a checkpoint * start operation. */ rectype = WT_LOGREC_SYSTEM; fmt = WT_UNCHECKED_STRING(I); WT_ERR(__wt_struct_size( session, &recsize, fmt, rectype)); WT_ERR(__wt_logrec_alloc(session, recsize, &logrec)); WT_ERR(__wt_struct_pack(session, (uint8_t *)logrec->data + logrec->size, recsize, fmt, rectype)); logrec->size += (uint32_t)recsize; WT_ERR(__wt_logop_checkpoint_start_pack( session, logrec)); WT_ERR(__wt_log_write(session, logrec, ckpt_lsn, 0)); } else { WT_ERR(__wt_log_printf(session, "CHECKPOINT: Starting record")); WT_ERR(__wt_log_flush_lsn(session, ckpt_lsn, true)); } /* * We take and immediately release the visibility lock. * Acquiring the write lock guarantees that any transaction * that has written to the log has also made its transaction * visible at this time. */ __wt_writelock(session, &txn_global->visibility_rwlock); __wt_writeunlock(session, &txn_global->visibility_rwlock); /* * We need to make sure that the log records in the checkpoint * LSN are on disk. In particular to make sure that the * current log file exists. */ WT_ERR(__wt_log_force_sync(session, ckpt_lsn)); break; case WT_TXN_LOG_CKPT_START: /* Take a copy of the transaction snapshot. */ txn->ckpt_nsnapshot = txn->snapshot_count; recsize = (size_t)txn->ckpt_nsnapshot * WT_INTPACK64_MAXSIZE; WT_ERR(__wt_scr_alloc(session, recsize, &txn->ckpt_snapshot)); p = txn->ckpt_snapshot->mem; end = p + recsize; for (i = 0; i < txn->snapshot_count; i++) WT_ERR(__wt_vpack_uint( &p, WT_PTRDIFF(end, p), txn->snapshot[i])); break; case WT_TXN_LOG_CKPT_STOP: /* * During a clean connection close, we get here without the * prepare or start steps. In that case, log the current LSN * as the checkpoint LSN. */ if (!txn->full_ckpt) { txn->ckpt_nsnapshot = 0; WT_CLEAR(empty); ckpt_snapshot = ∅ WT_ERR(__wt_log_flush_lsn(session, ckpt_lsn, true)); } else ckpt_snapshot = txn->ckpt_snapshot; /* Write the checkpoint log record. */ rectype = WT_LOGREC_CHECKPOINT; fmt = WT_UNCHECKED_STRING(IIIIu); WT_ERR(__wt_struct_size(session, &recsize, fmt, rectype, ckpt_lsn->l.file, ckpt_lsn->l.offset, txn->ckpt_nsnapshot, ckpt_snapshot)); WT_ERR(__wt_logrec_alloc(session, recsize, &logrec)); WT_ERR(__wt_struct_pack(session, (uint8_t *)logrec->data + logrec->size, recsize, fmt, rectype, ckpt_lsn->l.file, ckpt_lsn->l.offset, txn->ckpt_nsnapshot, ckpt_snapshot)); logrec->size += (uint32_t)recsize; WT_ERR(__wt_log_write(session, logrec, lsnp, F_ISSET(conn, WT_CONN_CKPT_SYNC) ? WT_LOG_FSYNC : 0)); /* * If this full checkpoint completed successfully and there is * no hot backup in progress and this is not an unclean * recovery, tell the logging subsystem the checkpoint LSN so * that it can archive. Do not update the logging checkpoint * LSN if this is during a clean connection close, only during * a full checkpoint. A clean close may not update any * metadata LSN and we do not want to archive in that case. */ if (!conn->hot_backup && (!FLD_ISSET(conn->log_flags, WT_CONN_LOG_RECOVER_DIRTY) || FLD_ISSET(conn->log_flags, WT_CONN_LOG_FORCE_DOWNGRADE)) && txn->full_ckpt) __wt_log_ckpt(session, ckpt_lsn); /* FALLTHROUGH */ case WT_TXN_LOG_CKPT_CLEANUP: /* Cleanup any allocated resources */ WT_INIT_LSN(ckpt_lsn); txn->ckpt_nsnapshot = 0; __wt_scr_free(session, &txn->ckpt_snapshot); txn->full_ckpt = false; break; WT_ILLEGAL_VALUE_ERR(session); } err: __wt_logrec_free(session, &logrec); return (ret); }
/* * __wt_txn_checkpoint_log -- * Write a log record for a checkpoint operation. */ int __wt_txn_checkpoint_log( WT_SESSION_IMPL *session, bool full, uint32_t flags, WT_LSN *lsnp) { WT_DECL_ITEM(logrec); WT_DECL_RET; WT_ITEM *ckpt_snapshot, empty; WT_LSN *ckpt_lsn; WT_TXN *txn; uint8_t *end, *p; size_t recsize; uint32_t i, rectype = WT_LOGREC_CHECKPOINT; const char *fmt = WT_UNCHECKED_STRING(IIQIU); txn = &session->txn; ckpt_lsn = &txn->ckpt_lsn; /* * If this is a file sync, log it unless there is a full checkpoint in * progress. */ if (!full) { if (txn->full_ckpt) { if (lsnp != NULL) *lsnp = *ckpt_lsn; return (0); } return (__txn_log_file_sync(session, flags, lsnp)); } switch (flags) { case WT_TXN_LOG_CKPT_PREPARE: txn->full_ckpt = true; WT_ERR(__wt_log_flush_lsn(session, ckpt_lsn, true)); /* * We need to make sure that the log records in the checkpoint * LSN are on disk. In particular to make sure that the * current log file exists. */ WT_ERR(__wt_log_force_sync(session, ckpt_lsn)); break; case WT_TXN_LOG_CKPT_START: /* Take a copy of the transaction snapshot. */ txn->ckpt_nsnapshot = txn->snapshot_count; recsize = txn->ckpt_nsnapshot * WT_INTPACK64_MAXSIZE; WT_ERR(__wt_scr_alloc(session, recsize, &txn->ckpt_snapshot)); p = txn->ckpt_snapshot->mem; end = p + recsize; for (i = 0; i < txn->snapshot_count; i++) WT_ERR(__wt_vpack_uint( &p, WT_PTRDIFF(end, p), txn->snapshot[i])); break; case WT_TXN_LOG_CKPT_STOP: /* * During a clean connection close, we get here without the * prepare or start steps. In that case, log the current LSN * as the checkpoint LSN. */ if (!txn->full_ckpt) { txn->ckpt_nsnapshot = 0; WT_CLEAR(empty); ckpt_snapshot = ∅ WT_ERR(__wt_log_flush_lsn(session, ckpt_lsn, true)); } else ckpt_snapshot = txn->ckpt_snapshot; /* Write the checkpoint log record. */ WT_ERR(__wt_struct_size(session, &recsize, fmt, rectype, ckpt_lsn->file, ckpt_lsn->offset, txn->ckpt_nsnapshot, ckpt_snapshot)); WT_ERR(__wt_logrec_alloc(session, recsize, &logrec)); WT_ERR(__wt_struct_pack(session, (uint8_t *)logrec->data + logrec->size, recsize, fmt, rectype, ckpt_lsn->file, ckpt_lsn->offset, txn->ckpt_nsnapshot, ckpt_snapshot)); logrec->size += (uint32_t)recsize; WT_ERR(__wt_log_write(session, logrec, lsnp, F_ISSET(S2C(session), WT_CONN_CKPT_SYNC) ? WT_LOG_FSYNC : 0)); /* * If this full checkpoint completed successfully and there is * no hot backup in progress, tell the logging subsystem the * checkpoint LSN so that it can archive. Do not update the * logging checkpoint LSN if this is during a clean connection * close, only during a full checkpoint. A clean close may not * update any metadata LSN and we do not want to archive in * that case. */ if (!S2C(session)->hot_backup && txn->full_ckpt) WT_ERR(__wt_log_ckpt(session, ckpt_lsn)); /* FALLTHROUGH */ case WT_TXN_LOG_CKPT_CLEANUP: /* Cleanup any allocated resources */ WT_INIT_LSN(ckpt_lsn); txn->ckpt_nsnapshot = 0; __wt_scr_free(session, &txn->ckpt_snapshot); txn->full_ckpt = false; break; WT_ILLEGAL_VALUE_ERR(session); } err: __wt_logrec_free(session, &logrec); return (ret); }
void test_value(int64_t val) { const uint8_t *cp; uint8_t buf[WT_INTPACK64_MAXSIZE + 8]; /* -Werror=array-bounds */ uint8_t *p; int64_t sinput, soutput; uint64_t uinput, uoutput; size_t used_len; memset(buf, 0xff, sizeof(buf)); /* -Werror=maybe-uninitialized */ sinput = val; soutput = 0; /* -Werror=maybe-uninitialized */ /* * Required on some systems to pull in parts of the library * for which we have data references. */ testutil_check(__wt_library_init()); p = buf; testutil_check(__wt_vpack_int(&p, sizeof(buf), sinput)); used_len = (size_t)(p - buf); testutil_assert(used_len <= WT_INTPACK64_MAXSIZE); cp = buf; testutil_check(__wt_vunpack_int(&cp, used_len, &soutput)); /* Ensure we got the correct value back */ if (sinput != soutput) { fprintf(stderr, "mismatch %" PRId64 ", %" PRId64 "\n", sinput, soutput); abort(); } /* Ensure that decoding used the correct amount of buffer */ if (cp != p) { fprintf(stderr, "Unpack consumed wrong size for %" PRId64 ", expected %" WT_SIZET_FMT ", got %" WT_SIZET_FMT "\n", sinput, used_len, cp > p ? used_len + (size_t)(cp - p) : /* More than buf used */ used_len - (size_t)(p - cp)); /* Less than buf used */ abort(); } /* Test unsigned, convert negative into bigger positive values */ uinput = (uint64_t)val; p = buf; testutil_check(__wt_vpack_uint(&p, sizeof(buf), uinput)); used_len = (size_t)(p - buf); testutil_assert(used_len <= WT_INTPACK64_MAXSIZE); cp = buf; testutil_check(__wt_vunpack_uint(&cp, sizeof(buf), &uoutput)); /* Ensure we got the correct value back */ if (sinput != soutput) { fprintf(stderr, "mismatch %" PRId64 ", %" PRId64 "\n", sinput, soutput); abort(); } /* Ensure that decoding used the correct amount of buffer */ if (cp != p) { fprintf(stderr, "Unpack consumed wrong size for %" PRId64 ", expected %" WT_SIZET_FMT ", got %" WT_SIZET_FMT "\n", sinput, used_len, cp > p ? used_len + (size_t)(cp - p) : used_len - (size_t)(p - cp)); abort(); } }