/* * __wt_turtle_init -- * Check the turtle file and create if necessary. */ int __wt_turtle_init(WT_SESSION_IMPL *session) { WT_DECL_RET; int exist, exist_incr; char *metaconf; metaconf = NULL; /* * Discard any turtle setup file left-over from previous runs. This * doesn't matter for correctness, it's just cleaning up random files. */ WT_RET(__wt_remove_if_exists(session, WT_METADATA_TURTLE_SET)); /* * We could die after creating the turtle file and before creating the * metadata file, or worse, the metadata file might be in some random * state. Make sure that doesn't happen: if we don't find the turtle * file, first create the metadata file, load any hot backup, and then * create the turtle file. No matter what happens, if metadata file * creation doesn't fully complete, we won't have a turtle file and we * will repeat the process until we succeed. * * Incremental backups can occur only run recovery is run and it becomes * live. So if there is a turtle file and an incremental backup file * that is an error. Otherwise, if there's already a turtle file, * we're done. */ WT_RET(__wt_exist(session, WT_INCREMENTAL_BACKUP, &exist_incr)); WT_RET(__wt_exist(session, WT_METADATA_TURTLE, &exist)); if (exist) { if (exist_incr) WT_RET_MSG(session, EINVAL, "Incremental backup after running recovery " "is not allowed."); return (0); } if (exist_incr) F_SET(S2C(session), WT_CONN_WAS_BACKUP); /* Create the metadata file. */ WT_RET(__metadata_init(session)); /* Load any hot-backup information. */ WT_RET(__metadata_load_hot_backup(session)); /* Create any bulk-loaded file stubs. */ WT_RET(__metadata_load_bulk(session)); /* Create the turtle file. */ WT_RET(__metadata_config(session, &metaconf)); WT_ERR(__wt_turtle_update(session, WT_METAFILE_URI, metaconf)); /* Remove the backup files, we'll never read them again. */ WT_ERR(__wt_backup_file_remove(session)); err: __wt_free(session, metaconf); return (ret); }
/* * __wt_turtle_init -- * Check the turtle file and create if necessary. */ int __wt_turtle_init(WT_SESSION_IMPL *session) { WT_DECL_RET; int exist; char *metaconf; metaconf = NULL; /* * Discard any turtle setup file left-over from previous runs. This * doesn't matter for correctness, it's just cleaning up random files. */ WT_RET(__wt_exist(session, WT_METADATA_TURTLE_SET, &exist)); if (exist) WT_RET(__wt_remove(session, WT_METADATA_TURTLE_SET)); /* * We could die after creating the turtle file and before creating the * metadata file, or worse, the metadata file might be in some random * state. Make sure that doesn't happen: if we don't find the turtle * file, first create the metadata file, load any hot backup, and then * create the turtle file. No matter what happens, if metadata file * creation doesn't fully complete, we won't have a turtle file and we * will repeat the process until we succeed. * * If there's already a turtle file, we're done. */ WT_RET(__wt_exist(session, WT_METADATA_TURTLE, &exist)); if (exist) return (0); /* Create the metadata file. */ WT_RET(__metadata_init(session)); /* Load any hot-backup information. */ WT_RET(__metadata_load_hot_backup(session)); /* Create any bulk-loaded file stubs. */ WT_RET(__metadata_load_bulk(session)); /* Create the turtle file. */ WT_RET(__metadata_config(session, &metaconf)); WT_ERR(__wt_turtle_update(session, WT_METAFILE_URI, metaconf)); /* Remove the backup file if it exists, we'll never read it again. */ WT_ERR(__wt_exist(session, WT_METADATA_BACKUP, &exist)); if (exist) WT_ERR(__wt_remove(session, WT_METADATA_BACKUP)); err: __wt_free(session, metaconf); return (ret); }
/* * __backup_file_remove -- * Remove the meta-data backup file. */ static int __backup_file_remove(WT_SESSION_IMPL *session) { WT_DECL_RET; int exist; WT_ERR(__wt_exist(session, WT_INCREMENTAL_BACKUP, &exist)); if (exist) WT_ERR(__wt_remove(session, WT_INCREMENTAL_BACKUP)); WT_ERR(__wt_exist(session, WT_METADATA_BACKUP, &exist)); if (exist) WT_ERR(__wt_remove(session, WT_METADATA_BACKUP)); err: return (ret); }
/* * __wt_lsm_tree_setup_chunk -- * Initialize a chunk of an LSM tree. */ int __wt_lsm_tree_setup_chunk( WT_SESSION_IMPL *session, WT_LSM_TREE *lsm_tree, WT_LSM_CHUNK *chunk) { const char *cfg[] = { WT_CONFIG_BASE(session, session_drop), "force", NULL }; int exists; WT_RET(__wt_epoch(session, &chunk->create_ts)); WT_RET(__wt_lsm_tree_chunk_name( session, lsm_tree, chunk->id, &chunk->uri)); /* * If the underlying file exists, drop the chunk first - there may be * some content hanging over from an aborted merge or checkpoint. * * Don't do this for the very first chunk: we are called during * WT_SESSION::create, and doing a drop inside there does interesting * things with handle locks and metadata tracking. It can never have * been the result of an interrupted merge, anyway. */ if (chunk->id > 1) { WT_RET(__wt_exist( session, chunk->uri + strlen("file:"), &exists)); if (exists) WT_RET(__wt_schema_drop(session, chunk->uri, cfg)); } return (__wt_schema_create(session, chunk->uri, lsm_tree->file_config)); }
/* * __drop_file -- * Drop a file. */ static int __drop_file(WT_SESSION_IMPL *session, const char *uri, int force) { int exist, ret; const char *filename; ret = 0; filename = uri; if (!WT_PREFIX_SKIP(filename, "file:")) return (EINVAL); /* If open, close the btree handle. */ WT_RET(__wt_session_close_any_open_btree(session, filename)); /* Remove the schema table entry (ignore missing items). */ WT_TRET(__wt_schema_table_remove(session, uri)); if (force && ret == WT_NOTFOUND) ret = 0; /* Remove the underlying physical file. */ exist = 0; WT_TRET(__wt_exist(session, filename, &exist)); if (exist) WT_TRET(__wt_remove(session, filename)); return (ret); }
/* * __rename_file -- * WT_SESSION::rename for a file. */ static int __rename_file( WT_SESSION_IMPL *session, const char *uri, const char *newuri) { WT_DECL_RET; int exist; const char *filename, *newfile, *newvalue, *oldvalue; newvalue = oldvalue = NULL; filename = uri; newfile = newuri; if (!WT_PREFIX_SKIP(filename, "file:") || !WT_PREFIX_SKIP(newfile, "file:")) return (EINVAL); /* Close any btree handles in the file. */ WT_ERR(__wt_conn_btree_close_all(session, uri)); /* * First, check if the file being renamed exists in the system. Doing * this check first matches the table rename behavior because we return * WT_NOTFOUND when the renamed file doesn't exist (subsequently mapped * to ENOENT by the session layer). */ WT_ERR(__wt_metadata_read(session, uri, &oldvalue)); /* * Check to see if the proposed name is already in use, in either the * metadata or the filesystem. */ switch (ret = __wt_metadata_read(session, newuri, &newvalue)) { case 0: WT_ERR_MSG(session, EEXIST, "%s", newuri); case WT_NOTFOUND: ret = 0; break; default: WT_ERR(ret); } WT_ERR(__wt_exist(session, newfile, &exist)); if (exist) WT_ERR_MSG(session, EEXIST, "%s", newfile); /* Replace the old file entries with new file entries. */ WT_ERR(__wt_metadata_remove(session, uri)); WT_ERR(__wt_metadata_insert(session, newuri, oldvalue)); /* Rename the underlying file. */ WT_ERR(__wt_rename(session, filename, newfile)); if (WT_META_TRACKING(session)) WT_ERR(__wt_meta_track_fileop(session, uri, newuri)); err: __wt_free(session, newvalue); __wt_free(session, oldvalue); return (ret); }
/*修改文件名操作*/ static int __rename_file(WT_SESSION_IMPL* session, const char* uri, const char* newuri) { WT_DECL_RET; int exist; const char *filename, *newfile; char *newvalue, *oldvalue; newvalue = oldvalue = NULL; filename = uri; newfile = newuri; if (!WT_PREFIX_SKIP(filename, "file:") || !WT_PREFIX_SKIP(newfile, "file:")) return (EINVAL); /*关闭这个文件对应的data source handler*/ WT_WITH_DHANDLE_LOCK(session, ret = __wt_conn_dhandle_close_all(session, uri, 0)); WT_ERR(ret); /* * First, check if the file being renamed exists in the system. Doing * this check first matches the table rename behavior because we return * WT_NOTFOUND when the renamed file doesn't exist (subsequently mapped * to ENOENT by the session layer). */ /*先查出旧的文件名uri对应的meta 信息,再用新的文件名uri旧版本的meta信息*/ WT_ERR(__wt_metadata_search(session, uri, &oldvalue)); switch (ret = __wt_metadata_search(session, newuri, &newvalue)) { case 0: WT_ERR_MSG(session, EEXIST, "%s", newuri); /* NOTREACHED */ case WT_NOTFOUND: break; default: WT_ERR(ret); } WT_ERR(__wt_exist(session, newfile, &exist)); if (exist) WT_ERR_MSG(session, EEXIST, "%s", newfile); /* Replace the old file entries with new file entries. */ WT_ERR(__wt_metadata_remove(session, uri)); WT_ERR(__wt_metadata_insert(session, newuri, oldvalue)); WT_ERR(__wt_rename(session, filename, newfile)); if(WT_META_TRACKING(session)) WT_ERR(__wt_meta_track_fileop(session, uri, newuri)); err: __wt_free(session, newvalue); __wt_free(session, oldvalue); return ret; }
/* * __wt_remove_if_exists -- * Remove a file if it exists. */ int __wt_remove_if_exists(WT_SESSION_IMPL *session, const char *name) { bool exist; WT_RET(__wt_exist(session, name, &exist)); if (exist) WT_RET(__wt_remove(session, name)); return (0); }
/* * __wt_meta_turtle_init -- * Check the turtle file and create if necessary. */ int __wt_meta_turtle_init(WT_SESSION_IMPL *session, int *existp) { WT_DECL_RET; WT_ITEM *buf; int exist; const char *metaconf; const char *cfg[] = API_CONF_DEFAULTS(file, meta, NULL); buf = NULL; metaconf = NULL; *existp = 0; /* Discard any turtle setup file left-over from previous runs. */ WT_RET(__wt_exist(session, WT_METADATA_TURTLE_SET, &exist)); if (exist) WT_RET(__wt_remove(session, WT_METADATA_TURTLE_SET)); /* If there's already a turtle file, we're done. */ WT_RET(__wt_exist(session, WT_METADATA_TURTLE, &exist)); if (exist) { *existp = 1; return (0); } /* Create a turtle file with default values. */ WT_ERR(__wt_scr_alloc(session, 0, &buf)); WT_ERR(__wt_buf_fmt(session, buf, "key_format=S,value_format=S,version=(major=%d,minor=%d)", WT_BTREE_MAJOR_VERSION, WT_BTREE_MINOR_VERSION)); cfg[1] = buf->data; WT_ERR(__wt_config_collapse(session, cfg, &metaconf)); WT_ERR(__wt_meta_turtle_update(session, WT_METADATA_URI, metaconf)); err: __wt_free(session, metaconf); __wt_scr_free(&buf); return (ret); }
/* * __rename_file -- * WT_SESSION::rename for a file. */ static int __rename_file( WT_SESSION_IMPL *session, const char *uri, const char *newuri) { WT_DECL_RET; int exist; const char *filename, *newfile, *value; value = NULL; filename = uri; newfile = newuri; if (!WT_PREFIX_SKIP(filename, "file:") || !WT_PREFIX_SKIP(newfile, "file:")) return (EINVAL); /* Close any btree handles in the file. */ WT_RET(__wt_conn_btree_close_all(session, uri)); /* * Check to see if the proposed name is already in use, in either * the metadata or the filesystem. */ switch (ret = __wt_metadata_read(session, newuri, &value)) { case 0: WT_ERR_MSG(session, EEXIST, "%s", newuri); case WT_NOTFOUND: ret = 0; break; default: WT_ERR(ret); } WT_ERR(__wt_exist(session, newfile, &exist)); if (exist) WT_ERR_MSG(session, EEXIST, "%s", newfile); /* Replace the old file entries with new file entries. */ WT_ERR(__wt_metadata_read(session, uri, &value)); WT_ERR(__wt_metadata_remove(session, uri)); WT_ERR(__wt_metadata_insert(session, newuri, value)); /* Rename the underlying file. */ WT_ERR(__wt_rename(session, filename, newfile)); if (WT_META_TRACKING(session)) WT_ERR(__wt_meta_track_fileop(session, uri, newuri)); err: __wt_free(session, value); return (ret); }
/* * __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 exist, match; *valuep = 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_exist(session, WT_METADATA_TURTLE, &exist)); if (!exist) return (strcmp(key, WT_METAFILE_URI) == 0 ? __metadata_config(session, valuep) : WT_NOTFOUND); WT_RET(__wt_fopen(session, WT_METADATA_TURTLE, WT_FHANDLE_READ, 0, &fp)); /* 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: WT_TRET(__wt_fclose(session, &fp, WT_FHANDLE_READ)); __wt_scr_free(session, &buf); return (ret); }
/* * __drop_file -- * Drop a file. */ static int __drop_file( WT_SESSION_IMPL *session, const char *uri, int force, const char *cfg[]) { WT_DECL_RET; int exist; const char *filename; filename = uri; if (!WT_PREFIX_SKIP(filename, "file:")) return (EINVAL); if (session->btree == NULL && (ret = __wt_session_get_btree(session, uri, NULL, cfg, WT_BTREE_EXCLUSIVE | WT_BTREE_LOCK_ONLY)) != 0) { if (ret == WT_NOTFOUND || ret == ENOENT) ret = 0; return (ret); } /* Close all btree handles associated with this file. */ WT_RET(__wt_conn_btree_close_all(session, uri)); /* Remove the metadata entry (ignore missing items). */ WT_TRET(__wt_metadata_remove(session, uri)); if (force && ret == WT_NOTFOUND) ret = 0; /* Remove the underlying physical file. */ exist = 0; WT_TRET(__wt_exist(session, filename, &exist)); if (exist) { /* * There is no point tracking this operation: there is no going * back from here. */ WT_TRET(__wt_remove(session, filename)); } return (ret); }
/* * __metadata_load_bulk -- * Create any bulk-loaded file stubs. */ static int __metadata_load_bulk(WT_SESSION_IMPL *session) { WT_CURSOR *cursor; WT_DECL_RET; uint32_t allocsize; int exist; const char *filecfg[] = { WT_CONFIG_BASE(session, file_meta), NULL }; const char *key; /* * If a file was being bulk-loaded during the hot backup, it will appear * in the metadata file, but the file won't exist. Create on demand. */ WT_ERR(__wt_metadata_cursor(session, NULL, &cursor)); while ((ret = cursor->next(cursor)) == 0) { WT_ERR(cursor->get_key(cursor, &key)); if (!WT_PREFIX_SKIP(key, "file:")) continue; /* If the file exists, it's all good. */ WT_ERR(__wt_exist(session, key, &exist)); if (exist) continue; /* * If the file doesn't exist, assume it's a bulk-loaded file; * retrieve the allocation size and re-create the file. */ WT_ERR(__wt_direct_io_size_check( session, filecfg, "allocation_size", &allocsize)); WT_ERR(__wt_block_manager_create(session, key, allocsize)); } WT_ERR_NOTFOUND_OK(ret); err: if (cursor != NULL) WT_TRET(cursor->close(cursor)); return (ret); }
/* * __drop_file -- * Drop a file. */ static int __drop_file( WT_SESSION_IMPL *session, const char *uri, int force, const char *cfg[]) { WT_CONFIG_ITEM cval; WT_DECL_RET; int exist, remove_files; const char *filename; WT_RET(__wt_config_gets(session, cfg, "remove_files", &cval)); remove_files = (cval.val != 0); filename = uri; if (!WT_PREFIX_SKIP(filename, "file:")) return (EINVAL); /* Close all btree handles associated with this file. */ WT_WITH_DHANDLE_LOCK(session, ret = __wt_conn_dhandle_close_all(session, uri, force)); WT_RET(ret); /* Remove the metadata entry (ignore missing items). */ WT_TRET(__wt_metadata_remove(session, uri)); if (!remove_files) return (ret); /* Remove the underlying physical file. */ exist = 0; WT_TRET(__wt_exist(session, filename, &exist)); if (exist) { /* * There is no point tracking this operation: there is no going * back from here. */ WT_TRET(__wt_remove(session, filename)); } 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; int exist; /* Look for a hot backup file: if we find it, load it. */ WT_RET(__wt_exist(session, WT_METADATA_BACKUP, &exist)); if (!exist) return (0); WT_RET(__wt_fopen(session, WT_METADATA_BACKUP, WT_FHANDLE_READ, 0, &fp)); /* 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: WT_TRET(__wt_fclose(session, &fp, WT_FHANDLE_READ)); __wt_scr_free(session, &key); __wt_scr_free(session, &value); return (ret); }
/* * __backup_start -- * Start a backup. */ static int __backup_start( WT_SESSION_IMPL *session, WT_CURSOR_BACKUP *cb, const char *cfg[]) { WT_CONNECTION_IMPL *conn; WT_DECL_RET; int exist, log_only, target_list; conn = S2C(session); cb->next = 0; cb->list = NULL; /* * Single thread hot backups: we're holding the schema lock, so we * know we'll serialize with other attempts to start a hot backup. */ if (conn->hot_backup) WT_RET_MSG( session, EINVAL, "there is already a backup cursor open"); /* * The hot backup copy is done outside of WiredTiger, which means file * blocks can't be freed and re-allocated until the backup completes. * The checkpoint code checks the backup flag, and if a backup cursor * is open checkpoints aren't discarded. We release the lock as soon * as we've set the flag, we don't want to block checkpoints, we just * want to make sure no checkpoints are deleted. The checkpoint code * holds the lock until it's finished the checkpoint, otherwise we * could start a hot backup that would race with an already-started * checkpoint. */ __wt_spin_lock(session, &conn->hot_backup_lock); conn->hot_backup = 1; __wt_spin_unlock(session, &conn->hot_backup_lock); /* Create the hot backup file. */ WT_ERR(__backup_file_create(session, cb, 0)); /* Add log files if logging is enabled. */ /* * If a list of targets was specified, work our way through them. * Else, generate a list of all database objects. * * Include log files if doing a full backup, and copy them before * copying data files to avoid rolling the metadata forward across * a checkpoint that completes during the backup. */ target_list = 0; WT_ERR(__backup_uri(session, cb, cfg, &target_list, &log_only)); if (!target_list) { WT_ERR(__backup_log_append(session, cb, 1)); WT_ERR(__backup_all(session, cb)); } /* Add the hot backup and standard WiredTiger files to the list. */ if (log_only) { /* * Close any hot backup file. * We're about to open the incremental backup file. */ if (cb->bfp != NULL) { WT_TRET(fclose(cb->bfp) == 0 ? 0 : __wt_errno()); cb->bfp = NULL; } WT_ERR(__backup_file_create(session, cb, log_only)); WT_ERR(__backup_list_append( session, cb, WT_INCREMENTAL_BACKUP)); } else { WT_ERR(__backup_list_append( session, cb, WT_METADATA_BACKUP)); WT_ERR(__wt_exist(session, WT_BASECONFIG, &exist)); if (exist) WT_ERR(__backup_list_append( session, cb, WT_BASECONFIG)); WT_ERR(__wt_exist(session, WT_USERCONFIG, &exist)); if (exist) WT_ERR(__backup_list_append( session, cb, WT_USERCONFIG)); WT_ERR(__backup_list_append(session, cb, WT_WIREDTIGER)); } err: /* Close the hot backup file. */ if (cb->bfp != NULL) { WT_TRET(fclose(cb->bfp) == 0 ? 0 : __wt_errno()); cb->bfp = NULL; } if (ret != 0) { WT_TRET(__backup_cleanup_handles(session, cb)); WT_TRET(__backup_stop(session)); } return (ret); }
/* * __conn_config_file -- * Read in any WiredTiger_config file in the home directory. */ static int __conn_config_file(WT_SESSION_IMPL *session, const char **cfg, WT_ITEM **cbufp) { WT_DECL_ITEM(cbuf); WT_DECL_RET; WT_FH *fh; off_t size; uint32_t len; int exist, quoted; uint8_t *p, *t; *cbufp = NULL; /* Returned buffer */ fh = NULL; /* Check for an optional configuration file. */ #define WT_CONFIGFILE "WiredTiger.config" WT_RET(__wt_exist(session, WT_CONFIGFILE, &exist)); if (!exist) return (0); /* Open the configuration file. */ WT_RET(__wt_open(session, WT_CONFIGFILE, 0, 0, 0, &fh)); WT_ERR(__wt_filesize(session, fh, &size)); if (size == 0) goto err; /* * Sanity test: a 100KB configuration file would be insane. (There's * no practical reason to limit the file size, but I can either limit * the file size to something rational, or I can add code to test if * the off_t size is larger than a uint32_t, which is more complicated * and a waste of time.) */ if (size > 100 * 1024) WT_ERR_MSG(session, EFBIG, WT_CONFIGFILE); len = (uint32_t)size; /* * Copy the configuration file into memory, with a little slop, I'm not * interested in debugging off-by-ones. * * The beginning of a file is the same as if we run into an unquoted * newline character, simplify the parsing loop by pretending that's * what we're doing. */ WT_ERR(__wt_scr_alloc(session, len + 10, &cbuf)); WT_ERR( __wt_read(session, fh, (off_t)0, len, ((uint8_t *)cbuf->mem) + 1)); ((uint8_t *)cbuf->mem)[0] = '\n'; cbuf->size = len + 1; /* * Collapse the file's lines into a single string: newline characters * are replaced with commas unless the newline is quoted or backslash * escaped. Comment lines (an unescaped newline where the next non- * white-space character is a hash), are discarded. */ for (quoted = 0, p = t = cbuf->mem; len > 0;) { /* * Backslash pairs pass through untouched, unless immediately * preceding a newline, in which case both the backslash and * the newline are discarded. Backslash characters escape * quoted characters, too, that is, a backslash followed by a * quote doesn't start or end a quoted string. */ if (*p == '\\' && len > 1) { if (p[1] != '\n') { *t++ = p[0]; *t++ = p[1]; } p += 2; len -= 2; continue; } /* * If we're in a quoted string, or starting a quoted string, * take all characters, including white-space and newlines. */ if (quoted || *p == '"') { if (*p == '"') quoted = !quoted; *t++ = *p++; --len; continue; } /* Everything else gets taken, except for newline characters. */ if (*p != '\n') { *t++ = *p++; --len; continue; } /* * Replace any newline characters with commas (and strings of * commas are safe). * * After any newline, skip to a non-white-space character; if * the next character is a hash mark, skip to the next newline. */ for (;;) { for (*t++ = ','; --len > 0 && isspace(*++p);) ; if (len == 0) break; if (*p != '#') break; while (--len > 0 && *++p != '\n') ; if (len == 0) break; } } *t = '\0'; #if 0 fprintf(stderr, "file config: {%s}\n", (const char *)cbuf->data); #endif /* Check the configuration string. */ WT_ERR(__wt_config_check( session, __wt_confchk_wiredtiger_open, cbuf->data, 0)); /* * The configuration file falls between the default configuration and * the wiredtiger_open() configuration, overriding the defaults but not * overriding the wiredtiger_open() configuration. */ while (cfg[1] != NULL) ++cfg; cfg[1] = cfg[0]; cfg[0] = cbuf->data; *cbufp = cbuf; if (0) { err: if (cbuf != NULL) __wt_buf_free(session, cbuf); } if (fh != NULL) WT_TRET(__wt_close(session, fh)); return (ret); }
/* * __lsm_bloom_create -- * Create a bloom filter for a chunk of the LSM tree that has been * checkpointed but not yet been merged. */ static int __lsm_bloom_create(WT_SESSION_IMPL *session, WT_LSM_TREE *lsm_tree, WT_LSM_CHUNK *chunk, u_int chunk_off) { WT_BLOOM *bloom; WT_CURSOR *src; WT_DECL_RET; WT_ITEM buf, key; WT_SESSION *wt_session; uint64_t insert_count; int exist; /* * Normally, the Bloom URI is populated when the chunk struct is * allocated. After an open, however, it may not have been. * Deal with that here. */ if (chunk->bloom_uri == NULL) { WT_CLEAR(buf); WT_RET(__wt_lsm_tree_bloom_name( session, lsm_tree, chunk->id, &buf)); chunk->bloom_uri = __wt_buf_steal(session, &buf, NULL); } /* * Drop the bloom filter first - there may be some content hanging over * from an aborted merge or checkpoint. */ wt_session = &session->iface; WT_RET(__wt_exist(session, chunk->bloom_uri + strlen("file:"), &exist)); if (exist) WT_RET(wt_session->drop(wt_session, chunk->bloom_uri, "force")); bloom = NULL; /* * This is merge-like activity, and we don't want compacts to give up * because we are creating a bunch of bloom filters before merging. */ ++lsm_tree->merge_progressing; WT_RET(__wt_bloom_create(session, chunk->bloom_uri, lsm_tree->bloom_config, chunk->count, lsm_tree->bloom_bit_count, lsm_tree->bloom_hash_count, &bloom)); /* Open a special merge cursor just on this chunk. */ WT_ERR(__wt_open_cursor(session, lsm_tree->name, NULL, NULL, &src)); F_SET(src, WT_CURSTD_RAW); WT_ERR(__wt_clsm_init_merge(src, chunk_off, chunk->id, 1)); F_SET(session, WT_SESSION_NO_CACHE); for (insert_count = 0; (ret = src->next(src)) == 0; insert_count++) { WT_ERR(src->get_key(src, &key)); WT_ERR(__wt_bloom_insert(bloom, &key)); } WT_ERR_NOTFOUND_OK(ret); WT_TRET(src->close(src)); WT_TRET(__wt_bloom_finalize(bloom)); WT_ERR(ret); F_CLR(session, WT_SESSION_NO_CACHE); /* Load the new Bloom filter into cache. */ WT_CLEAR(key); WT_ERR_NOTFOUND_OK(__wt_bloom_get(bloom, &key)); WT_VERBOSE_ERR(session, lsm, "LSM worker created bloom filter %s. " "Expected %" PRIu64 " items, got %" PRIu64, chunk->bloom_uri, chunk->count, insert_count); /* Ensure the bloom filter is in the metadata. */ WT_ERR(__wt_lsm_tree_lock(session, lsm_tree, 1)); F_SET_ATOMIC(chunk, WT_LSM_CHUNK_BLOOM); ret = __wt_lsm_meta_write(session, lsm_tree); ++lsm_tree->dsk_gen; WT_TRET(__wt_lsm_tree_unlock(session, lsm_tree)); if (ret != 0) WT_ERR_MSG(session, ret, "LSM bloom worker metadata write"); err: if (bloom != NULL) WT_TRET(__wt_bloom_close(bloom)); F_CLR(session, WT_SESSION_NO_CACHE); return (ret); }