diff options
author | Keith Bostic <keith@wiredtiger.com> | 2013-05-30 10:05:45 -0400 |
---|---|---|
committer | Keith Bostic <keith@wiredtiger.com> | 2013-05-30 10:05:45 -0400 |
commit | 89875776720570a20bad157b7dfd50fb498308e8 (patch) | |
tree | dd06acde9c177d0e38eeed7e42bcacfc404352fb | |
parent | 6660da16da1edbc0255452c72af8fa72a3f8a3ec (diff) | |
download | mongo-89875776720570a20bad157b7dfd50fb498308e8.tar.gz |
Change hot-backup to acquire a handle on each underlying file object to ensure
schema level operations (for example, drop), will be blocked until the backup
cursor closes.
-rw-r--r-- | src/cursor/cur_backup.c | 67 | ||||
-rw-r--r-- | src/include/cursor.h | 10 | ||||
-rw-r--r-- | src/include/wt_internal.h | 2 | ||||
-rw-r--r-- | src/lsm/lsm_worker.c | 24 |
4 files changed, 61 insertions, 42 deletions
diff --git a/src/cursor/cur_backup.c b/src/cursor/cur_backup.c index 53b1729aa0f..e5f3880753e 100644 --- a/src/cursor/cur_backup.c +++ b/src/cursor/cur_backup.c @@ -32,13 +32,13 @@ __curbackup_next(WT_CURSOR *cursor) cb = (WT_CURSOR_BACKUP *)cursor; CURSOR_API_CALL(cursor, session, next, NULL); - if (cb->list == NULL || cb->list[cb->next] == NULL) { + if (cb->list == NULL || cb->list[cb->next].name == NULL) { F_CLR(cursor, WT_CURSTD_KEY_SET); WT_ERR(WT_NOTFOUND); } - cb->iface.key.data = cb->list[cb->next]; - cb->iface.key.size = WT_STORE_SIZE(strlen(cb->list[cb->next]) + 1); + cb->iface.key.data = cb->list[cb->next].name; + cb->iface.key.size = WT_STORE_SIZE(strlen(cb->list[cb->next].name) + 1); ++cb->next; F_SET(cursor, WT_CURSTD_KEY_RET); @@ -76,22 +76,28 @@ static int __curbackup_close(WT_CURSOR *cursor) { WT_CURSOR_BACKUP *cb; + WT_CURSOR_BACKUP_ENTRY *p; WT_DECL_RET; WT_SESSION_IMPL *session; - char **p; int tret; cb = (WT_CURSOR_BACKUP *)cursor; CURSOR_API_CALL(cursor, session, close, NULL); - /* Free the list of files. */ + /* Release the handles, free the file names, free the list itself. */ if (cb->list != NULL) { - for (p = cb->list; *p != NULL; ++p) - __wt_free(session, *p); + for (p = cb->list; p->name != NULL; ++p) { + if (p->handle != NULL) + WT_WITH_DHANDLE(session, p->handle, + WT_TRET( + __wt_session_release_btree(session))); + __wt_free(session, p->name); + } + __wt_free(session, cb->list); } - ret = __wt_cursor_close(cursor); + WT_TRET(__wt_cursor_close(cursor)); session->bkp_cursor = NULL; WT_WITH_SCHEMA_LOCK(session, @@ -313,8 +319,7 @@ __backup_all(WT_SESSION_IMPL *session, WT_CURSOR_BACKUP *cb) break; if (strcmp(uri, WT_METADATA_URI) == 0) continue; - WT_ERR( - __backup_list_append(session, cb, uri + strlen("file:"))); + WT_ERR(__backup_list_append(session, cb, uri)); } WT_ERR_NOTFOUND_OK(ret); @@ -416,10 +421,9 @@ __wt_backup_list_append(WT_SESSION_IMPL *session, const char *name) WT_RET_TEST( (fprintf(cb->bfp, "%s\n%s\n", name, value) < 0), __wt_errno()); - /* Add to the list of files needing to be copied. */ + /* Add file type objects to the list of files to be copied. */ if (WT_PREFIX_MATCH(name, "file:")) - WT_RET( - __backup_list_append(session, cb, name + strlen("file:"))); + WT_RET(__backup_list_append(session, cb, name)); return (0); } @@ -430,12 +434,28 @@ __wt_backup_list_append(WT_SESSION_IMPL *session, const char *name) */ static int __backup_list_append( - WT_SESSION_IMPL *session, WT_CURSOR_BACKUP *cb, const char *name) + WT_SESSION_IMPL *session, WT_CURSOR_BACKUP *cb, const char *uri) { + WT_CURSOR_BACKUP_ENTRY *p; + WT_DATA_HANDLE *old_dhandle; + WT_DECL_RET; + const char *name; + int need_handle; + /* Leave a NULL at the end to mark the end of the list. */ if (cb->list_next + 1 * sizeof(char *) >= cb->list_allocated) WT_RET(__wt_realloc(session, &cb->list_allocated, (cb->list_next + 100) * sizeof(char *), &cb->list)); + p = &cb->list[cb->list_next]; + p[0].name = p[1].name = NULL; + p[0].handle = p[1].handle = NULL; + + need_handle = 0; + name = uri; + if (WT_PREFIX_MATCH(uri, "file:")) { + need_handle = 1; + name += strlen("file:"); + } /* * !!! @@ -446,9 +466,22 @@ __backup_list_append( * that for now, that block manager might not even support physical * copying of files by applications. */ - WT_RET(__wt_strdup( - session, name, &cb->list[cb->list_next++])); - cb->list[cb->list_next] = NULL; + WT_RET(__wt_strdup(session, name, &p->name)); + + /* + * If it's a file in the database, get a handle for the underlying + * object (this handle blocks schema level operations, for example + * WT_SESSION.drop or an LSM file discard after level merging). + */ + if (need_handle) { + old_dhandle = session->dhandle; + if ((ret = + __wt_session_get_btree(session, uri, NULL, NULL, 0)) == 0) + p->handle = session->dhandle; + session->dhandle = old_dhandle; + WT_RET(ret); + } + ++cb->list_next; return (0); } diff --git a/src/include/cursor.h b/src/include/cursor.h index d1af0aa2798..a86b4b5f702 100644 --- a/src/include/cursor.h +++ b/src/include/cursor.h @@ -52,15 +52,19 @@ 0 /* uint32_t flags */ \ } +struct __wt_cursor_backup_entry { + char *name; /* File name */ + WT_DATA_HANDLE *handle; /* Handle */ +}; struct __wt_cursor_backup { WT_CURSOR iface; size_t next; /* Cursor position */ + FILE *bfp; /* Backup file */ - size_t list_allocated; /* List of files */ + WT_CURSOR_BACKUP_ENTRY *list; /* List of files to be copied. */ + size_t list_allocated; size_t list_next; - char **list; - FILE *bfp; }; struct __wt_cursor_btree { diff --git a/src/include/wt_internal.h b/src/include/wt_internal.h index 71c5c433035..690d8c9fba3 100644 --- a/src/include/wt_internal.h +++ b/src/include/wt_internal.h @@ -99,6 +99,8 @@ struct __wt_connection_stats; typedef struct __wt_connection_stats WT_CONNECTION_STATS; struct __wt_cursor_backup; typedef struct __wt_cursor_backup WT_CURSOR_BACKUP; +struct __wt_cursor_backup_entry; + typedef struct __wt_cursor_backup_entry WT_CURSOR_BACKUP_ENTRY; struct __wt_cursor_btree; typedef struct __wt_cursor_btree WT_CURSOR_BTREE; struct __wt_cursor_bulk; diff --git a/src/lsm/lsm_worker.c b/src/lsm/lsm_worker.c index e039c3e20f8..bc892b3309a 100644 --- a/src/lsm/lsm_worker.c +++ b/src/lsm/lsm_worker.c @@ -432,17 +432,11 @@ __lsm_discard_handle( static int __lsm_drop_file(WT_SESSION_IMPL *session, const char *uri) { - WT_CONNECTION_IMPL *conn; WT_DECL_RET; const char *drop_cfg[] = { WT_CONFIG_BASE(session, session_drop), "remove_files=false", NULL }; - conn = S2C(session); - /* Give up early if a hot backup is in progress. */ - if (conn->hot_backup != 0) - return (EBUSY); - /* * We need to grab the schema lock to drop the file, so first try to * make sure there is minimal work to freeing space in the cache. @@ -452,27 +446,13 @@ __lsm_drop_file(WT_SESSION_IMPL *session, const char *uri) WT_RET(__lsm_discard_handle(session, uri, "WiredTigerCheckpoint")); /* - * Take the hot backup lock to prevent new backups starting. Don't - * proceed if a backup has started since we first checked. - */ - __wt_spin_lock(session, &conn->hot_backup_lock); - if (conn->hot_backup != 0) { - __wt_spin_unlock(session, &conn->hot_backup_lock); - return (EBUSY); - } - - /* * Take the schema lock for the drop operation. Play games with the * hot backup lock. Since __wt_schema_drop results in the hot backup * lock being taken when it updates the metadata (which would be too * late to prevent our drop). */ - __wt_spin_lock(session, &S2C(session)->schema_lock); - F_SET(session, WT_SESSION_SCHEMA_LOCKED); - __wt_spin_unlock(session, &conn->hot_backup_lock); - ret = __wt_schema_drop(session, uri, drop_cfg); - F_CLR(session, WT_SESSION_SCHEMA_LOCKED); - __wt_spin_unlock(session, &S2C(session)->schema_lock); + WT_WITH_SCHEMA_LOCK(session, + ret = __wt_schema_drop(session, uri, drop_cfg)); if (ret == 0) ret = __wt_remove(session, uri + strlen("file:")); |