/* * __curlog_close -- * WT_CURSOR.close method for the log cursor type. */ static int __curlog_close(WT_CURSOR *cursor) { WT_CONNECTION_IMPL *conn; WT_CURSOR_LOG *cl; WT_DECL_RET; WT_LOG *log; WT_SESSION_IMPL *session; CURSOR_API_CALL(cursor, session, close, NULL); cl = (WT_CURSOR_LOG *)cursor; conn = S2C(session); WT_ASSERT(session, FLD_ISSET(conn->log_flags, WT_CONN_LOG_ENABLED)); log = conn->log; WT_TRET(__wt_readunlock(session, log->log_archive_lock)); WT_TRET(__curlog_reset(cursor)); __wt_free(session, cl->cur_lsn); __wt_free(session, cl->next_lsn); __wt_scr_free(session, &cl->logrec); __wt_scr_free(session, &cl->opkey); __wt_scr_free(session, &cl->opvalue); __wt_free(session, cl->packed_key); __wt_free(session, cl->packed_value); WT_TRET(__wt_cursor_close(cursor)); err: API_END_RET(session, ret); }
/* * __bulk_row_keycmp_err -- * Error routine when row-store keys inserted out-of-order. */ static int __bulk_row_keycmp_err(WT_CURSOR_BULK *cbulk) { WT_CURSOR *cursor; WT_DECL_ITEM(a); WT_DECL_ITEM(b); WT_DECL_RET; WT_SESSION_IMPL *session; session = (WT_SESSION_IMPL *)cbulk->cbt.iface.session; cursor = &cbulk->cbt.iface; WT_ERR(__wt_scr_alloc(session, 512, &a)); WT_ERR(__wt_scr_alloc(session, 512, &b)); WT_ERR_MSG(session, EINVAL, "bulk-load presented with out-of-order keys: %s compares smaller " "than previously inserted key %s", __wt_buf_set_printable( session, cursor->key.data, cursor->key.size, a), __wt_buf_set_printable( session, cbulk->last.data, cbulk->last.size, b)); err: __wt_scr_free(session, &a); __wt_scr_free(session, &b); return (ret); }
/* * __curlog_close -- * WT_CURSOR.close method for the log cursor type. */ static int __curlog_close(WT_CURSOR *cursor) { WT_CONNECTION_IMPL *conn; WT_CURSOR_LOG *cl; WT_DECL_RET; WT_SESSION_IMPL *session; cl = (WT_CURSOR_LOG *)cursor; CURSOR_API_CALL_PREPARE_ALLOWED(cursor, session, close, NULL); err: conn = S2C(session); if (F_ISSET(cl, WT_CURLOG_ARCHIVE_LOCK)) { (void)__wt_atomic_sub32(&conn->log_cursors, 1); __wt_readunlock(session, &conn->log->log_archive_lock); } __wt_free(session, cl->cur_lsn); __wt_free(session, cl->next_lsn); __wt_scr_free(session, &cl->logrec); __wt_scr_free(session, &cl->opkey); __wt_scr_free(session, &cl->opvalue); __wt_free(session, cl->packed_key); __wt_free(session, cl->packed_value); __wt_cursor_close(cursor); API_END_RET(session, ret); }
/* * __dmsg_wrapup -- * Flush any remaining output, release resources. */ static int __dmsg_wrapup(WT_DBG *ds) { WT_ITEM *msg; WT_SESSION_IMPL *session; session = ds->session; msg = ds->msg; __wt_scr_free(session, &ds->tmp); /* * Discard the buffer -- it shouldn't have anything in it, but might * as well be cautious. */ if (msg != NULL) { if (msg->size != 0) WT_RET(__wt_msg(session, "%s", (char *)msg->mem)); __wt_scr_free(session, &ds->msg); } /* Close any file we opened. */ if (ds->fp != NULL) (void)fclose(ds->fp); return (0); }
/* * __wt_las_remove_block -- * Remove all records matching a key prefix from the lookaside store. */ int __wt_las_remove_block(WT_SESSION_IMPL *session, WT_CURSOR *cursor, uint32_t btree_id, const uint8_t *addr, size_t addr_size) { WT_DECL_ITEM(las_addr); WT_DECL_ITEM(las_key); WT_DECL_RET; uint64_t las_counter, las_txnid; uint32_t las_id; int exact; WT_ERR(__wt_scr_alloc(session, 0, &las_addr)); WT_ERR(__wt_scr_alloc(session, 0, &las_key)); /* * Search for the block's unique prefix and step through all matching * records, removing them. */ las_addr->data = addr; las_addr->size = addr_size; las_key->size = 0; cursor->set_key( cursor, btree_id, las_addr, (uint64_t)0, (uint32_t)0, las_key); if ((ret = cursor->search_near(cursor, &exact)) == 0 && exact < 0) ret = cursor->next(cursor); for (; ret == 0; ret = cursor->next(cursor)) { WT_ERR(cursor->get_key(cursor, &las_id, las_addr, &las_counter, &las_txnid, las_key)); /* * Confirm the search using the unique prefix; if not a match, * we're done searching for records for this page. */ if (las_id != btree_id || las_addr->size != addr_size || memcmp(las_addr->data, addr, addr_size) != 0) break; /* * Cursor opened overwrite=true: won't return WT_NOTFOUND should * another thread remove the record before we do, and the cursor * remains positioned in that case. */ WT_ERR(cursor->remove(cursor)); } WT_ERR_NOTFOUND_OK(ret); err: __wt_scr_free(session, &las_addr); __wt_scr_free(session, &las_key); return (ret); }
/* * __wt_to_utf8_string -- * Convert UTF-16 encoded string to UTF-8. */ int __wt_to_utf8_string( WT_SESSION_IMPL *session, const wchar_t* wide, WT_ITEM **outbuf) { DWORD windows_error; int bufferSize; WT_DECL_RET; bufferSize = WideCharToMultiByte( CP_UTF8, 0, wide, -1, NULL, 0, NULL, NULL); windows_error = __wt_getlasterror(); if (bufferSize == 0 && windows_error != ERROR_INSUFFICIENT_BUFFER) { __wt_errx(session, "WideCharToMultiByte: %s", __wt_formatmessage(session, windows_error)); return (__wt_map_windows_error(windows_error)); } WT_RET(__wt_scr_alloc(session, bufferSize, outbuf)); bufferSize = WideCharToMultiByte( CP_UTF8, 0, wide, -1, (*outbuf)->mem, bufferSize, NULL, NULL); if (bufferSize == 0) { windows_error = __wt_getlasterror(); __wt_scr_free(session, outbuf); __wt_errx(session, "WideCharToMultiByte: %s", __wt_formatmessage(session, windows_error)); return (__wt_map_windows_error(windows_error)); } (*outbuf)->size = bufferSize; return (0); }
/* * __wt_debug_offset -- * Read and dump a disk page in debugging mode, using a file * offset/size/checksum triplet. */ int __wt_debug_offset(WT_SESSION_IMPL *session, wt_off_t offset, uint32_t size, uint32_t cksum, const char *ofile) { WT_DECL_ITEM(buf); WT_DECL_RET; uint8_t addr[WT_BTREE_MAX_ADDR_COOKIE], *endp; WT_ASSERT(session, S2BT_SAFE(session) != NULL); /* * This routine depends on the default block manager's view of files, * where an address consists of a file offset, length, and checksum. * This is for debugging only: other block managers might not see a * file or address the same way, that's why there's no block manager * method. * * Convert the triplet into an address structure. */ endp = addr; WT_RET(__wt_block_addr_to_buffer( S2BT(session)->bm->block, &endp, offset, size, cksum)); /* * Read the address through the btree I/O functions (so the block is * decompressed as necessary). */ WT_RET(__wt_scr_alloc(session, 0, &buf)); WT_ERR(__wt_bt_read(session, buf, addr, WT_PTRDIFF(endp, addr))); ret = __wt_debug_disk(session, buf->mem, ofile); err: __wt_scr_free(session, &buf); return (ret); }
/* * __drop_tree -- * Drop an index or colgroup reference. */ static int __drop_tree(WT_SESSION_IMPL *session, WT_BTREE *btree, int force) { WT_ITEM *buf; int ret; ret = 0; /* Remove the schema table entry (ignore missing items). */ WT_TRET(__wt_schema_table_remove(session, btree->name)); if (force && ret == WT_NOTFOUND) ret = 0; /* * Drop the file. * __drop_file closes the WT_BTREE handle, so we copy the * WT_BTREE->filename field to make a URI. */ WT_ERR(__wt_scr_alloc(session, 0, &buf)); WT_ERR(__wt_buf_fmt(session, buf, "file:%s", btree->filename)); WT_ERR(__drop_file(session, buf->data, force)); err: __wt_scr_free(&buf); return (ret); }
/* * __ovfl_cache -- * Cache an overflow value. */ static int __ovfl_cache(WT_SESSION_IMPL *session, WT_PAGE *page, WT_CELL_UNPACK *unpack) { WT_DECL_ITEM(tmp); WT_DECL_RET; WT_OVFL_TRACK *track; /* Read the overflow value. */ WT_RET(__wt_scr_alloc(session, 1024, &tmp)); WT_ERR(__wt_dsk_cell_data_ref(session, page->type, unpack, tmp)); /* Allocating tracking structures as necessary. */ if (page->modify->ovfl_track == NULL) WT_ERR(__wt_ovfl_track_init(session, page)); track = page->modify->ovfl_track; /* Copy the overflow item into place. */ WT_ERR(__wt_realloc_def(session, &track->remove_allocated, track->remove_next + 1, &track->remove)); track->remove[track->remove_next].cell = unpack->cell; WT_ERR(__wt_memdup(session, tmp->data, tmp->size, &track->remove[track->remove_next].data)); track->remove[track->remove_next].size = tmp->size; ++track->remove_next; err: __wt_scr_free(session, &tmp); return (ret); }
/* * __wt_win_fs_size -- * Get the size of a file in bytes, by file name. */ int __wt_win_fs_size(WT_FILE_SYSTEM *file_system, WT_SESSION *wt_session, const char *name, wt_off_t *sizep) { DWORD windows_error; WIN32_FILE_ATTRIBUTE_DATA data; WT_DECL_ITEM(name_wide); WT_DECL_RET; WT_SESSION_IMPL *session; WT_UNUSED(file_system); session = (WT_SESSION_IMPL *)wt_session; WT_RET(__wt_to_utf16_string(session, name, &name_wide)); if (GetFileAttributesExW( name_wide->data, GetFileExInfoStandard, &data) == 0) { windows_error = __wt_getlasterror(); ret = __wt_map_windows_error(windows_error); __wt_err(session, ret, "%s: file-size: GetFileAttributesEx: %s", name, __wt_formatmessage(session, windows_error)); WT_ERR(ret); } *sizep = ((int64_t)data.nFileSizeHigh << 32) | data.nFileSizeLow; err: __wt_scr_free(session, &name_wide); return (ret); }
/* * __ovfl_reuse_verbose -- * Dump information about a reuse overflow record. */ static int __ovfl_reuse_verbose(WT_SESSION_IMPL *session, WT_PAGE *page, WT_OVFL_REUSE *reuse, const char *tag) { WT_DECL_ITEM(tmp); WT_DECL_RET; WT_RET(__wt_scr_alloc(session, 64, &tmp)); WT_ERR(__wt_verbose(session, WT_VERB_OVERFLOW, "reuse: %s%s%p %s (%s%s%s) {%.*s}", tag == NULL ? "" : tag, tag == NULL ? "" : ": ", page, __wt_addr_string( session, WT_OVFL_REUSE_ADDR(reuse), reuse->addr_size, tmp), F_ISSET(reuse, WT_OVFL_REUSE_INUSE) ? "inuse" : "", F_ISSET(reuse, WT_OVFL_REUSE_INUSE) && F_ISSET(reuse, WT_OVFL_REUSE_JUST_ADDED) ? ", " : "", F_ISSET(reuse, WT_OVFL_REUSE_JUST_ADDED) ? "just-added" : "", WT_MIN(reuse->value_size, 40), (char *)WT_OVFL_REUSE_VALUE(reuse))); err: __wt_scr_free(session, &tmp); return (ret); }
/* * __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 k, v; WT_DECL_ITEM(buf); WT_DECL_RET; size_t allocated, slot; char *config; *ckptbasep = NULL; ckptbase = NULL; allocated = slot = 0; config = NULL; /* Retrieve the metadata information for the file. */ WT_RET(__wt_metadata_search(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); for (; __wt_config_next(&ckptconf, &k, &v) == 0; ++slot) { WT_ERR(__wt_realloc_def( session, &allocated, slot + 1, &ckptbase)); ckpt = &ckptbase[slot]; WT_ERR(__ckpt_load(session, &k, &v, ckpt)); } } /* * 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. */ WT_ERR(__wt_realloc_def(session, &allocated, slot + 2, &ckptbase)); /* Sort in creation-order. */ qsort(ckptbase, slot, sizeof(WT_CKPT), __ckpt_compare_order); /* Return the array to our caller. */ *ckptbasep = ckptbase; if (0) { err: __wt_meta_ckptlist_free(session, &ckptbase); } __wt_free(session, config); __wt_scr_free(session, &buf); return (ret); }
/* * __win_fs_remove -- * Remove a file. */ static int __win_fs_remove(WT_FILE_SYSTEM *file_system, WT_SESSION *wt_session, const char *name, uint32_t flags) { DWORD windows_error; WT_DECL_ITEM(name_wide); WT_DECL_RET; WT_SESSION_IMPL *session; WT_UNUSED(file_system); WT_UNUSED(flags); session = (WT_SESSION_IMPL *)wt_session; WT_RET(__wt_to_utf16_string(session, name, &name_wide)); if (DeleteFileW(name_wide->data) == FALSE) { windows_error = __wt_getlasterror(); ret = __wt_map_windows_error(windows_error); __wt_err(session, ret, "%s: file-remove: DeleteFileW: %s", name, __wt_formatmessage(session, windows_error)); WT_ERR(ret); } err: __wt_scr_free(session, &name_wide); return (ret); }
/* * __metadata_config -- * Return the default configuration information for the metadata file. */ static int __metadata_config(WT_SESSION_IMPL *session, char **metaconfp) { WT_DECL_ITEM(buf); WT_DECL_RET; const char *cfg[] = { WT_CONFIG_BASE(session, file_meta), NULL, NULL }; char *metaconf; *metaconfp = NULL; metaconf = NULL; /* Create a turtle file with default values. */ WT_RET(__wt_scr_alloc(session, 0, &buf)); WT_ERR(__wt_buf_fmt(session, buf, "key_format=S,value_format=S,id=%d,version=(major=%d,minor=%d)", WT_METAFILE_ID, WT_BTREE_MAJOR_VERSION_MAX, WT_BTREE_MINOR_VERSION_MAX)); cfg[1] = buf->data; WT_ERR(__wt_config_collapse(session, cfg, &metaconf)); *metaconfp = metaconf; if (0) { err: __wt_free(session, metaconf); } __wt_scr_free(&buf); return (ret); }
/* * __wt_desc_init -- * Write a file's initial descriptor structure. */ int __wt_desc_init(WT_SESSION_IMPL *session, WT_FH *fh, uint32_t allocsize) { WT_BLOCK_DESC *desc; WT_DECL_ITEM(buf); WT_DECL_RET; /* Use a scratch buffer to get correct alignment for direct I/O. */ WT_RET(__wt_scr_alloc(session, allocsize, &buf)); memset(buf->mem, 0, allocsize); desc = buf->mem; desc->magic = WT_BLOCK_MAGIC; desc->majorv = WT_BLOCK_MAJOR_VERSION; desc->minorv = WT_BLOCK_MINOR_VERSION; /* Update the checksum. */ desc->cksum = 0; desc->cksum = __wt_cksum(desc, allocsize); ret = __wt_write(session, fh, (off_t)0, (size_t)allocsize, desc); __wt_scr_free(&buf); return (ret); }
/* * __wt_block_read_off_blind -- * Read the block at an offset, return the size and checksum, debugging * only. */ int __wt_block_read_off_blind(WT_SESSION_IMPL *session, WT_BLOCK *block, wt_off_t offset, uint32_t *sizep, uint32_t *checksump) { WT_BLOCK_HEADER *blk; WT_DECL_ITEM(tmp); WT_DECL_RET; *sizep = 0; *checksump = 0; /* * Make sure the buffer is large enough for the header and read the * the first allocation-size block. */ WT_RET(__wt_scr_alloc(session, block->allocsize, &tmp)); WT_ERR(__wt_read( session, block->fh, offset, (size_t)block->allocsize, tmp->mem)); blk = WT_BLOCK_HEADER_REF(tmp->mem); __wt_block_header_byteswap(blk); *sizep = blk->disk_size; *checksump = blk->checksum; err: __wt_scr_free(session, &tmp); return (ret); }
/* * __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); }
/* * __backup_uri -- * Backup a list of objects. */ static int __backup_uri(WT_SESSION_IMPL *session, WT_CURSOR_BACKUP *cb, const char *cfg[], int *foundp, int *log_only) { WT_CONFIG targetconf; WT_CONFIG_ITEM cval, k, v; WT_DECL_ITEM(tmp); WT_DECL_RET; int target_list; const char *uri; *foundp = 0; *log_only = 0; /* * If we find a non-empty target configuration string, we have a job, * otherwise it's not our problem. */ WT_RET(__wt_config_gets(session, cfg, "target", &cval)); WT_RET(__wt_config_subinit(session, &targetconf, &cval)); for (cb->list_next = 0, target_list = 0; (ret = __wt_config_next(&targetconf, &k, &v)) == 0; ++target_list) { /* If it is our first time through, allocate. */ if (target_list == 0) { *foundp = 1; WT_ERR(__wt_scr_alloc(session, 512, &tmp)); } WT_ERR(__wt_buf_fmt(session, tmp, "%.*s", (int)k.len, k.str)); uri = tmp->data; if (v.len != 0) WT_ERR_MSG(session, EINVAL, "%s: invalid backup target: URIs may need quoting", uri); /* * Handle log targets. We do not need to go through the * schema worker, just call the function to append them. * Set log_only only if it is our only URI target. */ if (WT_PREFIX_MATCH(uri, "log:")) { if (target_list == 0) *log_only = 1; else *log_only = 0; WT_ERR(__wt_backup_list_uri_append( session, uri, NULL)); } else WT_ERR(__wt_schema_worker(session, uri, NULL, __wt_backup_list_uri_append, cfg, 0)); } WT_ERR_NOTFOUND_OK(ret); err: __wt_scr_free(session, &tmp); return (ret); }
/* * __wt_metadata_load_backup -- * Load the contents of any hot backup file. */ int __wt_metadata_load_backup(WT_SESSION_IMPL *session) { FILE *fp; WT_DECL_ITEM(key); WT_DECL_ITEM(value); WT_DECL_RET; const char *path; fp = NULL; path = NULL; /* Look for a hot backup file: if we find it, load it. */ WT_RET(__wt_filename(session, WT_METADATA_BACKUP, &path)); if ((fp = fopen(path, "r")) == NULL) { __wt_free(session, path); return (0); } /* Read line pairs and load them into the metadata file. */ WT_ERR(__wt_scr_alloc(session, 512, &key)); WT_ERR(__wt_scr_alloc(session, 512, &value)); for (;;) { WT_ERR(__wt_getline(session, key, fp)); if (key->size == 0) break; WT_ERR(__wt_getline(session, value, fp)); if (value->size == 0) WT_ERR(__wt_illegal_value(session, WT_METADATA_BACKUP)); WT_ERR(__wt_metadata_update(session, key->data, value->data)); } /* Remove the hot backup file, it's only read (successfully) once. */ WT_ERR(__wt_remove(session, WT_METADATA_BACKUP)); err: if (fp != NULL) WT_TRET(fclose(fp) == 0 ? 0 : __wt_errno()); if (path != NULL) __wt_free(session, path); __wt_scr_free(&key); __wt_scr_free(&value); return (ret); }
/* * __curlog_close -- * WT_CURSOR.close method for the log cursor type. */ static int __curlog_close(WT_CURSOR *cursor) { WT_CURSOR_LOG *cl; WT_DECL_RET; WT_SESSION_IMPL *session; CURSOR_API_CALL(cursor, session, close, NULL); cl = (WT_CURSOR_LOG *)cursor; WT_ERR(__curlog_reset(cursor)); __wt_free(session, cl->cur_lsn); __wt_free(session, cl->next_lsn); __wt_scr_free(&cl->logrec); __wt_scr_free(&cl->opkey); __wt_scr_free(&cl->opvalue); WT_ERR(__wt_cursor_close(cursor)); err: API_END_RET(session, ret); }
/* * __win_fs_rename -- * Rename a file. */ static int __win_fs_rename(WT_FILE_SYSTEM *file_system, WT_SESSION *wt_session, const char *from, const char *to, uint32_t flags) { DWORD windows_error; WT_DECL_RET; WT_DECL_ITEM(from_wide); WT_DECL_ITEM(to_wide); WT_SESSION_IMPL *session; WT_UNUSED(file_system); WT_UNUSED(flags); session = (WT_SESSION_IMPL *)wt_session; WT_ERR(__wt_to_utf16_string(session, from, &from_wide)); WT_ERR(__wt_to_utf16_string(session, to, &to_wide)); /* * Check if file exists since Windows does not override the file if * it exists. */ if (GetFileAttributesW(to_wide->data) != INVALID_FILE_ATTRIBUTES) if (DeleteFileW(to_wide->data) == FALSE) { windows_error = __wt_getlasterror(); __wt_errx(session, "%s: file-rename: DeleteFileW: %s", to, __wt_formatmessage(session, windows_error)); WT_ERR(__wt_map_windows_error(windows_error)); } if (MoveFileW(from_wide->data, to_wide->data) == FALSE) { windows_error = __wt_getlasterror(); __wt_errx(session, "%s to %s: file-rename: MoveFileW: %s", from, to, __wt_formatmessage(session, windows_error)); WT_ERR(__wt_map_windows_error(windows_error)); } err: __wt_scr_free(session, &from_wide); __wt_scr_free(session, &to_wide); return (ret); }
/*btree file的compact操作*/ static int __compact_file(WT_SESSION_IMPL* session, const char* uri, const char* cfg[]) { WT_DECL_RET; WT_DECL_ITEM(t); WT_SESSION *wt_session; WT_TXN *txn; int i; struct timespec start_time; txn = &session->txn; wt_session = &session->iface; /* * File compaction requires checkpoints, which will fail in a * transactional context. Check now so the error message isn't * confusing. */ if(session->compact->file_count != 0 && F_ISSET(txn, TXN_RUNNING)) WT_ERR_MSG(session, EINVAL, " File compaction not permitted in a transaction"); /* * Force the checkpoint: we don't want to skip it because the work we * need to have done is done in the underlying block manager. */ WT_ERR(__wt_scr_alloc(session, 128, &t)); WT_ERR(__wt_buf_fmt(session, t, "target=(\"%s\"),force=1", uri)); WT_ERR(__wt_epoch(session, &start_time)); /* * We compact 10% of the file on each pass (but the overall size of the * file is decreasing each time, so we're not compacting 10% of the * original file each time). Try 100 times (which is clearly more than * we need); quit if we make no progress and check for a timeout each * time through the loop. */ for (i = 0; i < 100; ++i) { WT_ERR(wt_session->checkpoint(wt_session, t->data)); session->compaction = 0; WT_WITH_SCHEMA_LOCK(session, ret = __wt_schema_worker(session, uri, __wt_compact, NULL, cfg, 0)); WT_ERR(ret); if (!session->compaction) break; WT_ERR(wt_session->checkpoint(wt_session, t->data)); WT_ERR(wt_session->checkpoint(wt_session, t->data)); WT_ERR(__session_compact_check_timeout(session, start_time)); } err: __wt_scr_free(session, &t); }
/* * __wt_turtle_read -- * Read the turtle file. */ int __wt_turtle_read(WT_SESSION_IMPL *session, const char *key, char **valuep) { FILE *fp; WT_DECL_ITEM(buf); WT_DECL_RET; int match; char *path; *valuep = NULL; fp = NULL; path = NULL; /* * Open the turtle file; there's one case where we won't find the turtle * file, yet still succeed. We create the metadata file before creating * the turtle file, and that means returning the default configuration * string for the metadata file. */ WT_RET(__wt_filename(session, WT_METADATA_TURTLE, &path)); if ((fp = fopen(path, "r")) == NULL) ret = __wt_errno(); __wt_free(session, path); if (fp == NULL) return (strcmp(key, WT_METAFILE_URI) == 0 ? __metadata_config(session, valuep) : ret); /* Search for the key. */ WT_ERR(__wt_scr_alloc(session, 512, &buf)); for (match = 0;;) { WT_ERR(__wt_getline(session, buf, fp)); if (buf->size == 0) WT_ERR(WT_NOTFOUND); if (strcmp(key, buf->data) == 0) match = 1; /* Key matched: read the subsequent line for the value. */ WT_ERR(__wt_getline(session, buf, fp)); if (buf->size == 0) WT_ERR(__wt_illegal_value(session, WT_METADATA_TURTLE)); if (match) break; } /* Copy the value for the caller. */ WT_ERR(__wt_strdup(session, buf->data, valuep)); err: if (fp != NULL) WT_TRET(fclose(fp) == 0 ? 0 : __wt_errno()); __wt_scr_free(&buf); return (ret); }
/* * __desc_read -- * Read and verify the file's metadata. */ static int __desc_read(WT_SESSION_IMPL *session, WT_BLOCK *block) { WT_BLOCK_DESC *desc; WT_DECL_ITEM(buf); WT_DECL_RET; uint32_t cksum; /* Use a scratch buffer to get correct alignment for direct I/O. */ WT_RET(__wt_scr_alloc(session, block->allocsize, &buf)); /* Read the first allocation-sized block and verify the file format. */ WT_ERR(__wt_read( session, block->fh, (off_t)0, (size_t)block->allocsize, buf->mem)); desc = buf->mem; WT_ERR(__wt_verbose(session, WT_VERB_BLOCK, "%s: magic %" PRIu32 ", major/minor: %" PRIu32 "/%" PRIu32 ", checksum %#" PRIx32, block->name, desc->magic, desc->majorv, desc->minorv, desc->cksum)); /* * We fail the open if the checksum fails, or the magic number is wrong * or the major/minor numbers are unsupported for this version. This * test is done even if the caller is verifying or salvaging the file: * it makes sense for verify, and for salvage we don't overwrite files * without some reason to believe they are WiredTiger files. The user * may have entered the wrong file name, and is now frantically pounding * their interrupt key. */ cksum = desc->cksum; desc->cksum = 0; if (desc->magic != WT_BLOCK_MAGIC || cksum != __wt_cksum(desc, block->allocsize)) WT_ERR_MSG(session, WT_ERROR, "%s does not appear to be a WiredTiger file", block->name); if (desc->majorv > WT_BLOCK_MAJOR_VERSION || (desc->majorv == WT_BLOCK_MAJOR_VERSION && desc->minorv > WT_BLOCK_MINOR_VERSION)) WT_ERR_MSG(session, WT_ERROR, "unsupported WiredTiger file version: this build only " "supports major/minor versions up to %d/%d, and the file " "is version %d/%d", WT_BLOCK_MAJOR_VERSION, WT_BLOCK_MINOR_VERSION, desc->majorv, desc->minorv); err: __wt_scr_free(&buf); return (ret); }
/* * __metadata_load_hot_backup -- * Load the contents of any hot backup file. */ static int __metadata_load_hot_backup(WT_SESSION_IMPL *session) { FILE *fp; WT_DECL_ITEM(key); WT_DECL_ITEM(value); WT_DECL_RET; char *path; fp = NULL; path = NULL; /* Look for a hot backup file: if we find it, load it. */ WT_RET(__wt_filename(session, WT_METADATA_BACKUP, &path)); fp = fopen(path, "r"); __wt_free(session, path); if (fp == NULL) return (0); /* Read line pairs and load them into the metadata file. */ WT_ERR(__wt_scr_alloc(session, 512, &key)); WT_ERR(__wt_scr_alloc(session, 512, &value)); for (;;) { WT_ERR(__wt_getline(session, key, fp)); if (key->size == 0) break; WT_ERR(__wt_getline(session, value, fp)); if (value->size == 0) WT_ERR(__wt_illegal_value(session, WT_METADATA_BACKUP)); WT_ERR(__wt_metadata_update(session, key->data, value->data)); } F_SET(S2C(session), WT_CONN_WAS_BACKUP); err: if (fp != NULL) WT_TRET(fclose(fp) == 0 ? 0 : __wt_errno()); __wt_scr_free(&key); __wt_scr_free(&value); return (ret); }
/* * __win_fs_rename -- * Rename a file. */ static int __win_fs_rename(WT_FILE_SYSTEM *file_system, WT_SESSION *wt_session, const char *from, const char *to, uint32_t flags) { DWORD windows_error; WT_DECL_ITEM(from_wide); WT_DECL_ITEM(to_wide); WT_DECL_RET; WT_SESSION_IMPL *session; WT_UNUSED(file_system); WT_UNUSED(flags); session = (WT_SESSION_IMPL *)wt_session; WT_ERR(__wt_to_utf16_string(session, from, &from_wide)); WT_ERR(__wt_to_utf16_string(session, to, &to_wide)); /* * We want an atomic rename, but that's not guaranteed by MoveFileExW * (or by any MSDN API). Don't set the MOVEFILE_COPY_ALLOWED flag to * prevent the system from falling back to a copy and delete process. * Do set the MOVEFILE_WRITE_THROUGH flag so the window is as small * as possible, just in case. WiredTiger renames are done in a single * directory and we expect that to be an atomic metadata update on any * modern filesystem. */ if (MoveFileExW(from_wide->data, to_wide->data, MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH) == FALSE) { windows_error = __wt_getlasterror(); ret = __wt_map_windows_error(windows_error); __wt_err(session, ret, "%s to %s: file-rename: MoveFileExW: %s", from, to, __wt_formatmessage(session, windows_error)); WT_ERR(ret); } err: __wt_scr_free(session, &from_wide); __wt_scr_free(session, &to_wide); return (ret); }
/* * __wt_config_collapse -- * Collapse a set of configuration strings into newly allocated memory. * * This function takes a NULL-terminated list of configuration strings (where * the first one contains all the defaults and the values are in order from * least to most preferred, that is, the default values are least preferred), * and collapses them into newly allocated memory. The algorithm is to walk * the first of the configuration strings, and for each entry, search all of * the configuration strings for a final value, keeping the last value found. * * Notes: * Any key not appearing in the first configuration string is discarded * from the final result, because we'll never search for it. * * Nested structures aren't parsed. For example, imagine a configuration * string contains "key=(k2=v2,k3=v3)", and a subsequent string has * "key=(k4=v4)", the result will be "key=(k4=v4)", as we search for and * use the final value of "key", regardless of field overlap or missing * fields in the nested value. */ int __wt_config_collapse( WT_SESSION_IMPL *session, const char **cfg, char **config_ret) { WT_CONFIG cparser; WT_CONFIG_ITEM k, v; WT_DECL_ITEM(tmp); WT_DECL_RET; *config_ret = NULL; WT_RET(__wt_scr_alloc(session, 0, &tmp)); __wt_config_init(session, &cparser, cfg[0]); while ((ret = __wt_config_next(&cparser, &k, &v)) == 0) { if (k.type != WT_CONFIG_ITEM_STRING && k.type != WT_CONFIG_ITEM_ID) WT_ERR_MSG(session, EINVAL, "Invalid configuration key found: '%s'", k.str); WT_ERR(__wt_config_get(session, cfg, &k, &v)); /* Include the quotes around string keys/values. */ if (k.type == WT_CONFIG_ITEM_STRING) { --k.str; k.len += 2; } if (v.type == WT_CONFIG_ITEM_STRING) { --v.str; v.len += 2; } WT_ERR(__wt_buf_catfmt(session, tmp, "%.*s=%.*s,", (int)k.len, k.str, (int)v.len, v.str)); } /* We loop until error, and the expected error is WT_NOTFOUND. */ if (ret != WT_NOTFOUND) goto err; /* * If the caller passes us no valid configuration strings, we get here * with no bytes to copy -- that's OK, the underlying string copy can * handle empty strings. * * Strip any trailing comma. */ if (tmp->size != 0) --tmp->size; ret = __wt_strndup(session, tmp->data, tmp->size, config_ret); err: __wt_scr_free(session, &tmp); return (ret); }
/* * __cursor_key_order_check_row -- * Check key ordering for row-store cursor movements. */ static int __cursor_key_order_check_row( WT_SESSION_IMPL *session, WT_CURSOR_BTREE *cbt, bool next) { WT_BTREE *btree; WT_ITEM *key; WT_DECL_RET; WT_DECL_ITEM(a); WT_DECL_ITEM(b); int cmp; btree = S2BT(session); key = &cbt->iface.key; cmp = 0; /* -Werror=maybe-uninitialized */ if (cbt->lastkey->size != 0) WT_RET(__wt_compare( session, btree->collator, cbt->lastkey, key, &cmp)); if (cbt->lastkey->size == 0 || (next && cmp < 0) || (!next && cmp > 0)) return (__wt_buf_set(session, cbt->lastkey, cbt->iface.key.data, cbt->iface.key.size)); WT_ERR(__wt_scr_alloc(session, 512, &a)); WT_ERR(__wt_scr_alloc(session, 512, &b)); WT_PANIC_ERR(session, EINVAL, "WT_CURSOR.%s out-of-order returns: returned key %s then key %s", next ? "next" : "prev", __wt_buf_set_printable( session, cbt->lastkey->data, cbt->lastkey->size, a), __wt_buf_set_printable(session, key->data, key->size, b)); err: __wt_scr_free(session, &a); __wt_scr_free(session, &b); return (ret); }
/* * __ckpt_server_config -- * Parse and setup the checkpoint server options. */ static int __ckpt_server_config(WT_SESSION_IMPL *session, const char **cfg, int *startp) { WT_CONFIG_ITEM cval; WT_CONNECTION_IMPL *conn; WT_DECL_ITEM(tmp); WT_DECL_RET; char *p; conn = S2C(session); /* * The checkpoint configuration requires a wait time and/or a log * size -- if one is not set, we're not running at all. * Checkpoints based on log size also require logging be enabled. */ WT_RET(__wt_config_gets(session, cfg, "checkpoint.wait", &cval)); conn->ckpt_usecs = (long)cval.val * 1000000; WT_RET(__wt_config_gets(session, cfg, "checkpoint.log_size", &cval)); conn->ckpt_logsize = (wt_off_t)cval.val; __wt_log_written_reset(session); if ((conn->ckpt_usecs == 0 && conn->ckpt_logsize == 0) || (conn->ckpt_logsize && conn->ckpt_usecs == 0 && !FLD_ISSET(conn->log_flags, WT_CONN_LOG_ENABLED))) { *startp = 0; return (0); } *startp = 1; /* * The application can specify a checkpoint name, which we ignore if * it's our default. */ WT_RET(__wt_config_gets(session, cfg, "checkpoint.name", &cval)); if (cval.len != 0 && !WT_STRING_MATCH(WT_CHECKPOINT, cval.str, cval.len)) { WT_RET(__wt_checkpoint_name_ok(session, cval.str, cval.len)); WT_RET(__wt_scr_alloc(session, cval.len + 20, &tmp)); WT_ERR(__wt_buf_fmt( session, tmp, "name=%.*s", (int)cval.len, cval.str)); WT_ERR(__wt_strdup(session, tmp->data, &p)); __wt_free(session, conn->ckpt_config); conn->ckpt_config = p; } err: __wt_scr_free(session, &tmp); return (ret); }
/* * __wt_debug_addr_print -- * Print out an address. */ int __wt_debug_addr_print( WT_SESSION_IMPL *session, const uint8_t *addr, size_t addr_size) { WT_DECL_ITEM(buf); WT_DECL_RET; WT_RET(__wt_scr_alloc(session, 128, &buf)); ret = __wt_fprintf(stderr, "%s\n", __wt_addr_string(session, addr, addr_size, buf)); __wt_scr_free(session, &buf); return (ret); }