/* * __wt_turtle_update -- * Update the turtle file. */ int __wt_turtle_update(WT_SESSION_IMPL *session, const char *key, const char *value) { WT_FSTREAM *fs; WT_DECL_RET; int vmajor, vminor, vpatch; const char *version; fs = NULL; /* * Create the turtle setup file: we currently re-write it from scratch * every time. */ WT_RET(__wt_fopen(session, WT_METADATA_TURTLE_SET, WT_FS_OPEN_CREATE | WT_FS_OPEN_EXCLUSIVE, WT_STREAM_WRITE, &fs)); version = wiredtiger_version(&vmajor, &vminor, &vpatch); WT_ERR(__wt_fprintf(session, fs, "%s\n%s\n%s\n" "major=%d,minor=%d,patch=%d\n%s\n%s\n", WT_METADATA_VERSION_STR, version, WT_METADATA_VERSION, vmajor, vminor, vpatch, key, value)); /* Flush the stream and rename the file into place. */ ret = __wt_sync_and_rename( session, &fs, WT_METADATA_TURTLE_SET, WT_METADATA_TURTLE); /* Close any file handle left open, remove any temporary file. */ err: WT_TRET(__wt_fclose(session, &fs)); WT_TRET(__wt_remove_if_exists(session, WT_METADATA_TURTLE_SET, false)); return (ret); }
/* * __backup_file_create -- * Create the meta-data backup file. */ static int __backup_file_create( WT_SESSION_IMPL *session, WT_CURSOR_BACKUP *cb, bool incremental) { return (__wt_fopen(session, incremental ? WT_INCREMENTAL_BACKUP : WT_METADATA_BACKUP, WT_FHANDLE_WRITE, 0, &cb->bfp)); }
/* * __wt_turtle_read -- * Read the turtle file. */ int __wt_turtle_read(WT_SESSION_IMPL *session, const char *key, char **valuep) { WT_DECL_ITEM(buf); WT_DECL_RET; WT_FSTREAM *fs; bool 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_fs_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, 0, WT_STREAM_READ, &fs)); /* Search for the key. */ WT_ERR(__wt_scr_alloc(session, 512, &buf)); for (match = false;;) { WT_ERR(__wt_getline(session, fs, buf)); if (buf->size == 0) WT_ERR(WT_NOTFOUND); if (strcmp(key, buf->data) == 0) match = true; /* Key matched: read the subsequent line for the value. */ WT_ERR(__wt_getline(session, fs, buf)); 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, &fs)); __wt_scr_free(session, &buf); if (ret != 0) __wt_free(session, *valuep); return (ret); }
/* * __debug_config -- * Configure debugging output. */ static int __debug_config(WT_SESSION_IMPL *session, WT_DBG *ds, const char *ofile) { memset(ds, 0, sizeof(WT_DBG)); ds->session = session; WT_RET(__wt_scr_alloc(session, 512, &ds->tmp)); /* * If we weren't given a file, we use the default event handler, and * we'll have to buffer messages. */ if (ofile == NULL) return (__wt_scr_alloc(session, 512, &ds->msg)); /* If we're using a file, flush on each line. */ WT_RET(__wt_fopen(session, ofile, WT_FHANDLE_WRITE, 0, &ds->fp)); (void)setvbuf(ds->fp, NULL, _IOLBF, 0); return (0); }
/* * __huffman_confchk_file -- * Check for a Huffman configuration file and return the file name. */ static int __huffman_confchk_file( WT_SESSION_IMPL *session, WT_CONFIG_ITEM *v, int *is_utf8p, FILE **fpp) { FILE *fp; WT_DECL_RET; size_t len; char *fname; /* Look for a prefix and file name. */ len = 0; if (is_utf8p != NULL) *is_utf8p = 0; if (WT_PREFIX_MATCH(v->str, "utf8")) { if (is_utf8p != NULL) *is_utf8p = 1; len = strlen("utf8"); } else if (WT_PREFIX_MATCH(v->str, "utf16")) len = strlen("utf16"); if (len == 0 || len >= v->len) WT_RET_MSG(session, EINVAL, "illegal Huffman configuration: %.*s", (int)v->len, v->str); /* Check the file exists. */ WT_RET(__wt_strndup(session, v->str + len, v->len - len, &fname)); WT_ERR(__wt_fopen(session, fname, WT_FHANDLE_READ, WT_FOPEN_FIXED, &fp)); /* Optionally return the file handle. */ if (fpp == NULL) (void)__wt_fclose(&fp, WT_FHANDLE_READ); else *fpp = fp; err: __wt_free(session, fname); return (ret); }
/* * __metadata_load_hot_backup -- * Load the contents of any hot backup file. */ static int __metadata_load_hot_backup(WT_SESSION_IMPL *session) { WT_DECL_ITEM(key); WT_DECL_ITEM(value); WT_DECL_RET; WT_FSTREAM *fs; bool exist; /* Look for a hot backup file: if we find it, load it. */ WT_RET(__wt_fs_exist(session, WT_METADATA_BACKUP, &exist)); if (!exist) return (0); WT_RET(__wt_fopen(session, WT_METADATA_BACKUP, 0, WT_STREAM_READ, &fs)); /* 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, fs, key)); if (key->size == 0) break; WT_ERR(__wt_getline(session, fs, value)); 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, &fs)); __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; WT_FSTREAM *srcfs; const char *dest; bool exist, log_only, target_list; conn = S2C(session); srcfs = NULL; dest = NULL; cb->next = 0; cb->list = NULL; cb->list_next = 0; WT_RET(__wt_inmem_unsupported_op(session, "backup cursor")); /* * 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. * * We are holding the checkpoint and schema locks so schema operations * will not see the backup file list until it is complete and valid. */ __wt_writelock(session, &conn->hot_backup_lock); conn->hot_backup = true; conn->hot_backup_list = NULL; __wt_writeunlock(session, &conn->hot_backup_lock); /* We're the lock holder, we own cleanup. */ F_SET(cb, WT_CURBACKUP_LOCKER); /* * Create a temporary backup file. This must be opened before * generating the list of targets in backup_uri. This file will * later be renamed to the correct name depending on whether or not * we're doing an incremental backup. We need a temp file so that if * we fail or crash while filling it, the existence of a partial file * doesn't confuse restarting in the source database. */ WT_ERR(__wt_fopen(session, WT_BACKUP_TMP, WT_FS_OPEN_CREATE, WT_STREAM_WRITE, &cb->bfs)); /* * 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 = false; WT_ERR(__backup_uri(session, cfg, &target_list, &log_only)); if (!target_list) { WT_ERR(__backup_log_append(session, cb, true)); WT_ERR(__backup_all(session)); } /* Add the hot backup and standard WiredTiger files to the list. */ if (log_only) { /* * We also open an incremental backup source file so that we * can detect a crash with an incremental backup existing in * the source directory versus an improper destination. */ dest = WT_INCREMENTAL_BACKUP; WT_ERR(__wt_fopen(session, WT_INCREMENTAL_SRC, WT_FS_OPEN_CREATE, WT_STREAM_WRITE, &srcfs)); WT_ERR(__backup_list_append( session, cb, WT_INCREMENTAL_BACKUP)); } else { dest = WT_METADATA_BACKUP; WT_ERR(__backup_list_append(session, cb, WT_METADATA_BACKUP)); WT_ERR(__wt_fs_exist(session, WT_BASECONFIG, &exist)); if (exist) WT_ERR(__backup_list_append( session, cb, WT_BASECONFIG)); WT_ERR(__wt_fs_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. */ WT_TRET(__wt_fclose(session, &cb->bfs)); if (srcfs != NULL) WT_TRET(__wt_fclose(session, &srcfs)); if (ret == 0) { WT_ASSERT(session, dest != NULL); WT_TRET(__wt_fs_rename(session, WT_BACKUP_TMP, dest, false)); __wt_writelock(session, &conn->hot_backup_lock); conn->hot_backup_list = cb->list; __wt_writeunlock(session, &conn->hot_backup_lock); } return (ret); }