/* * __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; bool 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); /* Close any btree handles in the file. */ WT_WITH_HANDLE_LIST_LOCK(session, ret = __wt_conn_dhandle_close_all(session, uri, false)); 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). */ WT_ERR(__wt_metadata_search(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_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_fs_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_fs_rename(session, filename, newfile, false)); 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; }
/* * __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_schema_truncate -- * WT_SESSION::truncate without a range. */ int __wt_schema_truncate( WT_SESSION_IMPL *session, const char *uri, const char *cfg[]) { WT_DATA_SOURCE *dsrc; WT_DECL_RET; const char *tablename; tablename = uri; if (WT_PREFIX_MATCH(uri, "file:")) { ret = __truncate_file(session, uri); } else if (WT_PREFIX_MATCH(uri, "lsm:")) ret = __wt_lsm_tree_truncate(session, uri, cfg); else if (WT_PREFIX_SKIP(tablename, "table:")) ret = __truncate_table(session, tablename, cfg); else if ((dsrc = __wt_schema_get_source(session, uri)) != NULL) ret = dsrc->truncate == NULL ? __truncate_dsrc(session, uri) : dsrc->truncate( dsrc, &session->iface, uri, (WT_CONFIG_ARG *)cfg); else ret = __wt_bad_object_type(session, uri); /* If we didn't find a metadata entry, map that error to ENOENT. */ return (ret == WT_NOTFOUND ? ENOENT : ret); }
/* * __drop_file -- * Drop a file. */ static int __drop_file( WT_SESSION_IMPL *session, const char *uri, bool force, const char *cfg[]) { WT_CONFIG_ITEM cval; WT_DECL_RET; bool 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_HANDLE_LIST_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); /* * Schedule the remove of the underlying physical file when the drop * completes. */ WT_TRET(__wt_meta_track_drop(session, filename)); return (ret); }
/*修改表名*/ static int __rename_table(WT_SESSION_IMPL *session, const char *uri, const char *newuri, const char *cfg[]) { WT_DECL_RET; WT_TABLE *table; u_int i; const char *oldname; oldname = uri; (void)WT_PREFIX_SKIP(oldname, "table:"); WT_RET(__wt_schema_get_table(session, oldname, strlen(oldname), 0, &table)); /* Rename the column groups. */ for (i = 0; i < WT_COLGROUPS(table); i++) WT_ERR(__rename_tree(session, table, newuri, table->cgroups[i]->name, cfg)); /* Rename the indices. */ WT_ERR(__wt_schema_open_indices(session, table)); for (i = 0; i < table->nindices; i++) WT_ERR(__rename_tree(session, table, newuri, table->indices[i]->name, cfg)); WT_ERR(__wt_schema_remove_table(session, table)); table = NULL; /* Rename the table. */ WT_ERR(__metadata_rename(session, uri, newuri)); }
/* * __truncate_file -- * WT_SESSION::truncate for a file. */ static int __truncate_file(WT_SESSION_IMPL *session, const char *name) { WT_DECL_RET; const char *filename; uint32_t allocsize; filename = name; if (!WT_PREFIX_SKIP(filename, "file:")) return (EINVAL); /* Open and lock the file. */ WT_RET(__wt_session_get_btree( session, name, NULL, NULL, WT_DHANDLE_EXCLUSIVE)); /* Get the allocation size. */ allocsize = S2BT(session)->allocsize; WT_RET(__wt_session_release_btree(session)); /* Close any btree handles in the file. */ WT_WITH_DHANDLE_LOCK(session, ret = __wt_conn_dhandle_close_all(session, name, 0)); WT_RET(ret); /* Delete the root address and truncate the file. */ WT_RET(__wt_meta_checkpoint_clear(session, name)); WT_RET(__wt_block_manager_truncate(session, filename, allocsize)); return (0); }
/* * __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); }
/* * __wt_schema_rename -- * WT_SESSION::rename. */ int __wt_schema_rename(WT_SESSION_IMPL *session, const char *uri, const char *newuri, const char *cfg[]) { WT_DATA_SOURCE *dsrc; WT_DECL_RET; const char *oldname, *newname; WT_UNUSED(cfg); /* Disallow renames to/from the WiredTiger name space. */ WT_RET(__wt_schema_name_check(session, uri)); WT_RET(__wt_schema_name_check(session, newuri)); /* * We track rename operations, if we fail in the middle, we want to * back it all out. */ WT_RET(__wt_meta_track_on(session)); oldname = uri; newname = newuri; if (WT_PREFIX_SKIP(oldname, "file:")) { if (!WT_PREFIX_SKIP(newname, "file:")) WT_RET_MSG(session, EINVAL, "rename target type must match URI: %s to %s", uri, newuri); ret = __rename_file(session, uri, newuri); } else if (WT_PREFIX_SKIP(oldname, "table:")) { if (!WT_PREFIX_SKIP(newname, "table:")) WT_RET_MSG(session, EINVAL, "rename target type must match URI: %s to %s", uri, newuri); ret = __rename_table(session, oldname, newname); } else if ((ret = __wt_schema_get_source(session, oldname, &dsrc)) == 0) ret = dsrc->rename(dsrc, &session->iface, oldname, newname, cfg[1]); WT_TRET(__wt_meta_track_off(session, ret != 0)); /* If we didn't find a metadata entry, map that error to ENOENT. */ return (ret == WT_NOTFOUND ? ENOENT : ret); }
/* * __drop_table -- * WT_SESSION::drop for a table. */ static int __drop_table(WT_SESSION_IMPL *session, const char *uri, const char *cfg[]) { WT_COLGROUP *colgroup; WT_DECL_RET; WT_INDEX *idx; WT_TABLE *table; const char *name; u_int i; name = uri; (void)WT_PREFIX_SKIP(name, "table:"); table = NULL; WT_ERR(__wt_schema_get_table( session, name, strlen(name), true, &table)); /* Drop the column groups. */ for (i = 0; i < WT_COLGROUPS(table); i++) { if ((colgroup = table->cgroups[i]) == NULL) continue; /* * Drop the column group before updating the metadata to avoid * the metadata for the table becoming inconsistent if we can't * get exclusive access. */ WT_ERR(__wt_schema_drop(session, colgroup->source, cfg)); WT_ERR(__wt_metadata_remove(session, colgroup->name)); } /* Drop the indices. */ WT_ERR(__wt_schema_open_indices(session, table)); for (i = 0; i < table->nindices; i++) { if ((idx = table->indices[i]) == NULL) continue; /* * Drop the column group before updating the metadata to avoid * the metadata for the table becoming inconsistent if we can't * get exclusive access. */ WT_ERR(__wt_schema_drop(session, idx->source, cfg)); WT_ERR(__wt_metadata_remove(session, idx->name)); } WT_ERR(__wt_schema_remove_table(session, table)); table = NULL; /* Remove the metadata entry (ignore missing items). */ WT_ERR(__wt_metadata_remove(session, uri)); err: if (table != NULL) __wt_schema_release_table(session, table); return (ret); }
/* * __drop_colgroup -- * WT_SESSION::drop for a colgroup. */ static int __drop_colgroup( WT_SESSION_IMPL *session, const char *uri, int force, const char *cfg[]) { WT_BTREE *btree; WT_TABLE *table; const char *cgname, *tablename; size_t tlen; int i, ret; tablename = uri; if (!WT_PREFIX_SKIP(tablename, "colgroup:")) return (EINVAL); cgname = strchr(tablename, ':'); if (cgname != NULL) { tlen = (size_t)(cgname - tablename); ++cgname; } else tlen = strlen(tablename); /* * Try to get the btree handle. Ideally, we would use an exclusive * lock here to prevent access to the table while we are dropping it, * but conflicts with the exclusive lock taken by * __wt_session_close_any_open_btree. If two threads race dropping * the same object, it will be caught there. * * If we can't get a tree, try to remove it from the schema table. */ if ((ret = __wt_schema_get_btree( session, uri, strlen(uri), cfg, WT_BTREE_NO_LOCK)) != 0) { (void)__wt_schema_table_remove(session, uri); return (ret); } btree = session->btree; /* If we can get the table, detach the colgroup from it. */ if ((ret = __wt_schema_get_table( session, tablename, tlen, &table)) == 0) { for (i = 0; i < WT_COLGROUPS(table); i++) { if (table->colgroup[i] == btree) { table->colgroup[i] = NULL; table->cg_complete = 0; break; } } } else if (ret != WT_NOTFOUND) WT_TRET(ret); WT_TRET(__drop_tree(session, btree, force)); return (ret); }
/* * __wt_schema_colgroup_name -- * Get the URI for a column group. This is used for metadata lookups. * The only complexity here is that simple tables (with a single column * group) use a simpler naming scheme. */ int __wt_schema_colgroup_name(WT_SESSION_IMPL *session, WT_TABLE *table, const char *cgname, size_t len, WT_ITEM *buf) { const char *tablename; tablename = table->name; (void)WT_PREFIX_SKIP(tablename, "table:"); return ((table->ncolgroups == 0) ? __wt_buf_fmt(session, buf, "colgroup:%s", tablename) : __wt_buf_fmt(session, buf, "colgroup:%s:%.*s", tablename, (int)len, cgname)); }
/* * __wt_schema_get_index -- * Find an index by URI. */ int __wt_schema_get_index(WT_SESSION_IMPL *session, const char *uri, bool quiet, WT_TABLE **tablep, WT_INDEX **indexp) { WT_DECL_RET; WT_INDEX *idx; WT_TABLE *table; const char *tablename, *tend; u_int i; *indexp = NULL; tablename = uri; if (!WT_PREFIX_SKIP(tablename, "index:") || (tend = strchr(tablename, ':')) == NULL) return (__wt_bad_object_type(session, uri)); WT_RET(__wt_schema_get_table(session, tablename, WT_PTRDIFF(tend, tablename), false, &table)); /* Try to find the index in the table. */ for (i = 0; i < table->nindices; i++) { idx = table->indices[i]; if (idx != NULL && strcmp(idx->name, uri) == 0) { if (tablep != NULL) *tablep = table; else __wt_schema_release_table(session, table); *indexp = idx; return (0); } } /* Otherwise, open it. */ WT_ERR(__wt_schema_open_index( session, table, tend + 1, strlen(tend + 1), indexp)); if (tablep != NULL) *tablep = table; err: __wt_schema_release_table(session, table); WT_RET(ret); if (*indexp != NULL) return (0); if (quiet) WT_RET(ENOENT); WT_RET_MSG(session, ENOENT, "%s not found in table", uri); }
/* * __wt_lsm_tree_set_chunk_size -- * Set the size of the chunk. Should only be called for chunks that are * on disk, or about to become on disk. */ int __wt_lsm_tree_set_chunk_size( WT_SESSION_IMPL *session, WT_LSM_CHUNK *chunk) { wt_off_t size; const char *filename; filename = chunk->uri; if (!WT_PREFIX_SKIP(filename, "file:")) WT_RET_MSG(session, EINVAL, "Expected a 'file:' URI: %s", chunk->uri); WT_RET(__wt_filesize_name(session, filename, &size)); chunk->size = (uint64_t)size; return (0); }
/* * __truncate_file -- * WT_SESSION::truncate for a file. */ static int __truncate_file(WT_SESSION_IMPL *session, const char *name) { const char *filename; filename = name; if (!WT_PREFIX_SKIP(filename, "file:")) return (EINVAL); /* Close any btree handles in the file. */ WT_RET(__wt_conn_btree_close_all(session, name)); /* Delete the root address and truncate the file. */ WT_RET(__wt_meta_checkpoint_clear(session, name)); WT_RET(__wt_block_manager_truncate(session, filename)); return (0); }
/* * __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; bool exist; const char *filecfg[] = { WT_CONFIG_BASE(session, file_meta), NULL, NULL }; const char *key, *value; /* * 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_RET(__wt_metadata_cursor(session, &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_fs_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(cursor->get_value(cursor, &value)); filecfg[1] = value; 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: WT_TRET(__wt_metadata_cursor_release(session, &cursor)); return (ret); }
/* * __rename_table -- * WT_SESSION::rename for a table. */ static int __rename_table(WT_SESSION_IMPL *session, const char *uri, const char *newuri, const char *cfg[]) { WT_DECL_ITEM(buf); WT_DECL_RET; WT_TABLE *table; u_int i; const char *oldname, *value; oldname = uri; (void)WT_PREFIX_SKIP(oldname, "table:"); WT_RET(__wt_schema_get_table( session, oldname, strlen(oldname), 0, &table)); /* Rename the column groups. */ for (i = 0; i < WT_COLGROUPS(table); i++) WT_ERR(__rename_tree(session, table, newuri, table->cgroups[i]->name, cfg)); /* Rename the indices. */ WT_ERR(__wt_schema_open_indices(session, table)); for (i = 0; i < table->nindices; i++) WT_ERR(__rename_tree(session, table, newuri, table->indices[i]->name, cfg)); __wt_schema_remove_table(session, table); table = NULL; /* Rename the table. */ WT_ERR(__wt_scr_alloc(session, 0, &buf)); WT_ERR(__wt_metadata_read(session, uri, &value)); WT_ERR(__wt_metadata_remove(session, uri)); WT_ERR(__wt_metadata_insert(session, newuri, value)); err: __wt_scr_free(&buf); if (table != NULL) __wt_schema_release_table(session, table); return (ret); }
/* * __wt_schema_truncate -- * WT_SESSION::truncate. */ int __wt_schema_truncate( WT_SESSION_IMPL *session, const char *uri, const char *cfg[]) { WT_DATA_SOURCE *dsrc; WT_DECL_RET; const char *tablename; WT_UNUSED(cfg); tablename = uri; if (WT_PREFIX_MATCH(uri, "file:")) ret = __truncate_file(session, uri); else if (WT_PREFIX_SKIP(tablename, "table:")) ret = __truncate_table(session, tablename); else if ((ret = __wt_schema_get_source(session, uri, &dsrc)) == 0) ret = dsrc->truncate(dsrc, &session->iface, uri, cfg); /* If we didn't find a metadata entry, map that error to ENOENT. */ return (ret == WT_NOTFOUND ? ENOENT : ret); }
/* * __drop_table -- * WT_SESSION::drop for a table. */ static int __drop_table(WT_SESSION_IMPL *session, const char *uri, int force) { WT_BTREE *btree; WT_TABLE *table; int i, ret; const char *name; ret = 0; name = uri; (void)WT_PREFIX_SKIP(name, "table:"); WT_ERR(__wt_schema_get_table(session, name, strlen(name), &table)); /* Drop the column groups. */ for (i = 0; i < WT_COLGROUPS(table); i++) { if ((btree = table->colgroup[i]) == NULL) continue; table->colgroup[i] = NULL; WT_TRET(__drop_tree(session, btree, force)); } /* Drop the indices. */ WT_TRET(__wt_schema_open_index(session, table, NULL, 0)); for (i = 0; i < table->nindices; i++) { btree = table->index[i]; table->index[i] = NULL; WT_TRET(__drop_tree(session, btree, force)); } WT_TRET(__wt_schema_remove_table(session, table)); /* Remove the schema table entry (ignore missing items). */ WT_TRET(__wt_schema_table_remove(session, uri)); err: if (force && ret == WT_NOTFOUND) ret = 0; 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); }
/* * __wt_schema_get_colgroup -- * Find a column group by URI. */ int __wt_schema_get_colgroup(WT_SESSION_IMPL *session, const char *uri, bool quiet, WT_TABLE **tablep, WT_COLGROUP **colgroupp) { WT_COLGROUP *colgroup; WT_TABLE *table; const char *tablename, *tend; u_int i; *colgroupp = NULL; tablename = uri; if (!WT_PREFIX_SKIP(tablename, "colgroup:")) return (__wt_bad_object_type(session, uri)); if ((tend = strchr(tablename, ':')) == NULL) tend = tablename + strlen(tablename); WT_RET(__wt_schema_get_table(session, tablename, WT_PTRDIFF(tend, tablename), false, &table)); for (i = 0; i < WT_COLGROUPS(table); i++) { colgroup = table->cgroups[i]; if (strcmp(colgroup->name, uri) == 0) { *colgroupp = colgroup; if (tablep != NULL) *tablep = table; else __wt_schema_release_table(session, table); return (0); } } __wt_schema_release_table(session, table); if (quiet) WT_RET(ENOENT); WT_RET_MSG(session, ENOENT, "%s not found in table", uri); }
/* * __wt_curjoin_open -- * Initialize a join cursor. * * Join cursors are read-only. */ int __wt_curjoin_open(WT_SESSION_IMPL *session, const char *uri, WT_CURSOR *owner, const char *cfg[], WT_CURSOR **cursorp) { WT_CURSOR_STATIC_INIT(iface, __curjoin_get_key, /* get-key */ __curjoin_get_value, /* get-value */ __wt_cursor_set_key_notsup, /* set-key */ __wt_cursor_set_value_notsup, /* set-value */ __wt_cursor_compare_notsup, /* compare */ __wt_cursor_equals_notsup, /* equals */ __curjoin_next, /* next */ __wt_cursor_notsup, /* prev */ __curjoin_reset, /* reset */ __wt_cursor_notsup, /* search */ __wt_cursor_search_near_notsup, /* search-near */ __wt_cursor_notsup, /* insert */ __wt_cursor_modify_notsup, /* modify */ __wt_cursor_notsup, /* update */ __wt_cursor_notsup, /* remove */ __wt_cursor_notsup, /* reserve */ __wt_cursor_reconfigure_notsup, /* reconfigure */ __wt_cursor_notsup, /* cache */ __wt_cursor_reopen_notsup, /* reopen */ __curjoin_close); /* close */ WT_CURSOR *cursor; WT_CURSOR_JOIN *cjoin; WT_DECL_ITEM(tmp); WT_DECL_RET; WT_TABLE *table; size_t size; const char *tablename, *columns; WT_STATIC_ASSERT(offsetof(WT_CURSOR_JOIN, iface) == 0); if (owner != NULL) WT_RET_MSG(session, EINVAL, "unable to initialize a join cursor with existing owner"); tablename = uri; if (!WT_PREFIX_SKIP(tablename, "join:table:")) return ( __wt_unexpected_object_type(session, uri, "join:table:")); columns = strchr(tablename, '('); if (columns == NULL) size = strlen(tablename); else size = WT_PTRDIFF(columns, tablename); WT_RET(__wt_schema_get_table( session, tablename, size, false, 0, &table)); WT_RET(__wt_calloc_one(session, &cjoin)); cursor = (WT_CURSOR *)cjoin; *cursor = iface; cursor->session = (WT_SESSION *)session; cursor->key_format = table->key_format; cursor->value_format = table->value_format; cjoin->table = table; /* Handle projections. */ WT_ERR(__wt_scr_alloc(session, 0, &tmp)); if (columns != NULL) { WT_ERR(__wt_struct_reformat(session, table, columns, strlen(columns), NULL, false, tmp)); WT_ERR(__wt_strndup( session, tmp->data, tmp->size, &cursor->value_format)); WT_ERR(__wt_strdup(session, columns, &cjoin->projection)); } WT_ERR(__wt_cursor_init(cursor, uri, owner, cfg, cursorp)); if (0) { err: WT_TRET(__curjoin_close(cursor)); *cursorp = NULL; } __wt_scr_free(session, &tmp); return (ret); }
/* * __schema_open_index -- * Open one or more indices for a table (internal version). */ static int __schema_open_index(WT_SESSION_IMPL *session, WT_TABLE *table, const char *idxname, size_t len, WT_INDEX **indexp) { WT_CURSOR *cursor; WT_DECL_ITEM(tmp); WT_DECL_RET; WT_INDEX *idx; u_int i; int cmp; bool match; const char *idxconf, *name, *tablename, *uri; /* Check if we've already done the work. */ if (idxname == NULL && table->idx_complete) return (0); cursor = NULL; idx = NULL; match = false; /* Build a search key. */ tablename = table->name; (void)WT_PREFIX_SKIP(tablename, "table:"); WT_ERR(__wt_scr_alloc(session, 512, &tmp)); WT_ERR(__wt_buf_fmt(session, tmp, "index:%s:", tablename)); /* Find matching indices. */ WT_ERR(__wt_metadata_cursor(session, &cursor)); cursor->set_key(cursor, tmp->data); if ((ret = cursor->search_near(cursor, &cmp)) == 0 && cmp < 0) ret = cursor->next(cursor); for (i = 0; ret == 0; i++, ret = cursor->next(cursor)) { WT_ERR(cursor->get_key(cursor, &uri)); name = uri; if (!WT_PREFIX_SKIP(name, tmp->data)) break; /* Is this the index we are looking for? */ match = idxname == NULL || WT_STRING_MATCH(name, idxname, len); /* * Ensure there is space, including if we have to make room for * a new entry in the middle of the list. */ WT_ERR(__wt_realloc_def(session, &table->idx_alloc, WT_MAX(i, table->nindices) + 1, &table->indices)); /* Keep the in-memory list in sync with the metadata. */ cmp = 0; while (table->indices[i] != NULL && (cmp = strcmp(uri, table->indices[i]->name)) > 0) { /* Index no longer exists, remove it. */ __wt_free(session, table->indices[i]); memmove(&table->indices[i], &table->indices[i + 1], (table->nindices - i) * sizeof(WT_INDEX *)); table->indices[--table->nindices] = NULL; } if (cmp < 0) { /* Make room for a new index. */ memmove(&table->indices[i + 1], &table->indices[i], (table->nindices - i) * sizeof(WT_INDEX *)); table->indices[i] = NULL; ++table->nindices; } if (!match) continue; if (table->indices[i] == NULL) { WT_ERR(cursor->get_value(cursor, &idxconf)); WT_ERR(__wt_calloc_one(session, &idx)); WT_ERR(__wt_strdup(session, uri, &idx->name)); WT_ERR(__wt_strdup(session, idxconf, &idx->config)); WT_ERR(__open_index(session, table, idx)); /* * If we're checking the creation of an index before a * table is fully created, don't save the index: it * will need to be reopened once the table is complete. */ if (!table->cg_complete) { WT_ERR( __wt_schema_destroy_index(session, &idx)); if (idxname != NULL) break; continue; } table->indices[i] = idx; idx = NULL; /* * If the slot is bigger than anything else we've seen, * bump the number of indices. */ if (i >= table->nindices) table->nindices = i + 1; } /* If we were looking for a single index, we're done. */ if (indexp != NULL) *indexp = table->indices[i]; if (idxname != NULL) break; } WT_ERR_NOTFOUND_OK(ret); if (idxname != NULL && !match) ret = WT_NOTFOUND; /* If we did a full pass, we won't need to do it again. */ if (idxname == NULL) { table->nindices = i; table->idx_complete = true; } err: WT_TRET(__wt_metadata_cursor_release(session, &cursor)); WT_TRET(__wt_schema_destroy_index(session, &idx)); __wt_scr_free(session, &tmp); return (ret); }
/* * __rename_tree -- * Rename an index or colgroup reference. */ static int __rename_tree(WT_SESSION_IMPL *session, WT_TABLE *table, const char *newuri, const char *name, const char *cfg[]) { WT_CONFIG_ITEM cval; WT_DECL_ITEM(nn); WT_DECL_ITEM(ns); WT_DECL_ITEM(nv); WT_DECL_ITEM(os); WT_DECL_RET; bool is_colgroup; const char *newname, *olduri, *suffix; char *value; olduri = table->name; value = NULL; newname = newuri; (void)WT_PREFIX_SKIP(newname, "table:"); /* * Create the new data source URI and update the schema value. * * 'name' has the format (colgroup|index):<tablename>[:<suffix>]; * we need the suffix. */ is_colgroup = WT_PREFIX_MATCH(name, "colgroup:"); if (!is_colgroup && !WT_PREFIX_MATCH(name, "index:")) WT_ERR_MSG(session, EINVAL, "expected a 'colgroup:' or 'index:' source: '%s'", name); suffix = strchr(name, ':'); /* An existing table should have a well formed name. */ WT_ASSERT(session, suffix != NULL); suffix = strchr(suffix + 1, ':'); WT_ERR(__wt_scr_alloc(session, 0, &nn)); WT_ERR(__wt_buf_fmt(session, nn, "%s%s%s", is_colgroup ? "colgroup:" : "index:", newname, (suffix == NULL) ? "" : suffix)); /* Skip the colon, if any. */ if (suffix != NULL) ++suffix; /* Read the old schema value. */ WT_ERR(__wt_metadata_search(session, name, &value)); /* * Calculate the new data source URI. Use the existing table structure * and substitute the new name temporarily. */ WT_ERR(__wt_scr_alloc(session, 0, &ns)); table->name = newuri; if (is_colgroup) WT_ERR(__wt_schema_colgroup_source( session, table, suffix, value, ns)); else WT_ERR(__wt_schema_index_source( session, table, suffix, value, ns)); if ((ret = __wt_config_getones(session, value, "source", &cval)) != 0) WT_ERR_MSG(session, EINVAL, "index or column group has no data source: %s", value); /* Take a copy of the old data source. */ WT_ERR(__wt_scr_alloc(session, 0, &os)); WT_ERR(__wt_buf_fmt(session, os, "%.*s", (int)cval.len, cval.str)); /* Overwrite it with the new data source. */ WT_ERR(__wt_scr_alloc(session, 0, &nv)); WT_ERR(__wt_buf_fmt(session, nv, "%.*s%s%s", (int)WT_PTRDIFF(cval.str, value), value, (const char *)ns->data, cval.str + cval.len)); /* * Do the rename before updating the metadata to avoid leaving the * metadata inconsistent if the rename fails. */ WT_ERR(__wt_schema_rename(session, os->data, ns->data, cfg)); /* * Remove the old metadata entry. * Insert the new metadata entry. */ WT_ERR(__wt_metadata_remove(session, name)); WT_ERR(__wt_metadata_insert(session, nn->data, nv->data)); err: __wt_scr_free(session, &nn); __wt_scr_free(session, &ns); __wt_scr_free(session, &nv); __wt_scr_free(session, &os); __wt_free(session, value); table->name = olduri; return (ret); }
/* * __wt_curindex_open -- * WT_SESSION->open_cursor method for index cursors. */ int __wt_curindex_open(WT_SESSION_IMPL *session, const char *uri, WT_CURSOR *owner, const char *cfg[], WT_CURSOR **cursorp) { WT_CURSOR_STATIC_INIT(iface, __wt_cursor_get_key, /* get-key */ __curindex_get_value, /* get-value */ __wt_cursor_set_key, /* set-key */ __curindex_set_value, /* set-value */ __curindex_compare, /* compare */ __wt_cursor_equals, /* equals */ __curindex_next, /* next */ __curindex_prev, /* prev */ __curindex_reset, /* reset */ __curindex_search, /* search */ __curindex_search_near, /* search-near */ __wt_cursor_notsup, /* insert */ __wt_cursor_notsup, /* update */ __wt_cursor_notsup, /* remove */ __wt_cursor_reconfigure_notsup, /* reconfigure */ __curindex_close); /* close */ WT_CURSOR_INDEX *cindex; WT_CURSOR *cursor; WT_DECL_ITEM(tmp); WT_DECL_RET; WT_INDEX *idx; WT_TABLE *table; const char *columns, *idxname, *tablename; size_t namesize; tablename = uri; if (!WT_PREFIX_SKIP(tablename, "index:") || (idxname = strchr(tablename, ':')) == NULL) WT_RET_MSG(session, EINVAL, "Invalid cursor URI: '%s'", uri); namesize = (size_t)(idxname - tablename); ++idxname; if ((ret = __wt_schema_get_table(session, tablename, namesize, false, &table)) != 0) { if (ret == WT_NOTFOUND) WT_RET_MSG(session, EINVAL, "Cannot open cursor '%s' on unknown table", uri); return (ret); } columns = strchr(idxname, '('); if (columns == NULL) namesize = strlen(idxname); else namesize = (size_t)(columns - idxname); if ((ret = __wt_schema_open_index( session, table, idxname, namesize, &idx)) != 0) { __wt_schema_release_table(session, table); return (ret); } WT_RET(__wt_calloc_one(session, &cindex)); cursor = &cindex->iface; *cursor = iface; cursor->session = &session->iface; cindex->table = table; cindex->index = idx; cindex->key_plan = idx->key_plan; cindex->value_plan = idx->value_plan; cursor->internal_uri = idx->name; cursor->key_format = idx->idxkey_format; cursor->value_format = table->value_format; /* * XXX * A very odd corner case is an index with a recno key. * The only way to get here is by creating an index on a column store * using only the primary's recno as the index key. Disallow that for * now. */ if (WT_CURSOR_RECNO(cursor)) WT_ERR_MSG(session, WT_ERROR, "Column store indexes based on a record number primary " "key are not supported"); /* Handle projections. */ if (columns != NULL) { WT_ERR(__wt_scr_alloc(session, 0, &tmp)); WT_ERR(__wt_struct_reformat(session, table, columns, strlen(columns), NULL, false, tmp)); WT_ERR(__wt_strndup( session, tmp->data, tmp->size, &cursor->value_format)); WT_ERR(__wt_buf_init(session, tmp, 0)); WT_ERR(__wt_struct_plan(session, table, columns, strlen(columns), false, tmp)); WT_ERR(__wt_strndup( session, tmp->data, tmp->size, &cindex->value_plan)); } WT_ERR(__wt_cursor_init( cursor, cursor->internal_uri, owner, cfg, cursorp)); WT_ERR(__wt_open_cursor( session, idx->source, cursor, cfg, &cindex->child)); /* Open the column groups needed for this index cursor. */ WT_ERR(__curindex_open_colgroups(session, cindex, cfg)); if (F_ISSET(cursor, WT_CURSTD_DUMP_JSON)) __wt_json_column_init( cursor, table->key_format, &idx->colconf, &table->colconf); if (0) { err: WT_TRET(__curindex_close(cursor)); *cursorp = NULL; } __wt_scr_free(session, &tmp); return (ret); }
/* * __create_colgroup -- * Create a column group. */ static int __create_colgroup(WT_SESSION_IMPL *session, const char *name, int exclusive, const char *config) { WT_CONFIG_ITEM cval; WT_DECL_RET; WT_ITEM confbuf, fmt, namebuf; WT_TABLE *table; size_t tlen; const char **cfgp, *cfg[4] = { WT_CONFIG_BASE(session, colgroup_meta), config, NULL, NULL }; const char *sourcecfg[] = { config, NULL, NULL }; const char *cgname, *source, *sourceconf, *tablename; char *cgconf, *oldconf; sourceconf = NULL; cgconf = oldconf = NULL; WT_CLEAR(fmt); WT_CLEAR(confbuf); WT_CLEAR(namebuf); tablename = name; if (!WT_PREFIX_SKIP(tablename, "colgroup:")) return (EINVAL); cgname = strchr(tablename, ':'); if (cgname != NULL) { tlen = (size_t)(cgname - tablename); ++cgname; } else tlen = strlen(tablename); if ((ret = __wt_schema_get_table(session, tablename, tlen, 1, &table)) != 0) WT_RET_MSG(session, (ret == WT_NOTFOUND) ? ENOENT : ret, "Can't create '%s' for non-existent table '%.*s'", name, (int)tlen, tablename); /* Make sure the column group is referenced from the table. */ if (cgname != NULL && (ret = __wt_config_subgets(session, &table->cgconf, cgname, &cval)) != 0) WT_ERR_MSG(session, EINVAL, "Column group '%s' not found in table '%.*s'", cgname, (int)tlen, tablename); /* Find the first NULL entry in the cfg stack. */ for (cfgp = &cfg[1]; *cfgp; cfgp++) ; /* Add the source to the colgroup config before collapsing. */ if (__wt_config_getones( session, config, "source", &cval) == 0 && cval.len != 0) { WT_ERR(__wt_buf_fmt( session, &namebuf, "%.*s", (int)cval.len, cval.str)); source = namebuf.data; } else { WT_ERR(__wt_schema_colgroup_source( session, table, cgname, config, &namebuf)); source = namebuf.data; WT_ERR(__wt_buf_fmt( session, &confbuf, "source=\"%s\"", source)); *cfgp++ = confbuf.data; } /* Calculate the key/value formats: these go into the source config. */ WT_ERR(__wt_buf_fmt(session, &fmt, "key_format=%s", table->key_format)); if (cgname == NULL) WT_ERR(__wt_buf_catfmt (session, &fmt, ",value_format=%s", table->value_format)); else { if (__wt_config_getones(session, config, "columns", &cval) != 0) WT_ERR_MSG(session, EINVAL, "No 'columns' configuration for '%s'", name); WT_ERR(__wt_buf_catfmt(session, &fmt, ",value_format=")); WT_ERR(__wt_struct_reformat(session, table, cval.str, cval.len, NULL, 1, &fmt)); } sourcecfg[1] = fmt.data; WT_ERR(__wt_config_merge(session, sourcecfg, NULL, &sourceconf)); WT_ERR(__wt_schema_create(session, source, sourceconf)); WT_ERR(__wt_config_collapse(session, cfg, &cgconf)); if ((ret = __wt_metadata_insert(session, name, cgconf)) != 0) { /* * If the entry already exists in the metadata, we're done. * This is an error for exclusive creates but okay otherwise. */ if (ret == WT_DUPLICATE_KEY) ret = exclusive ? EEXIST : 0; goto err; } WT_ERR(__wt_schema_open_colgroups(session, table)); err: __wt_free(session, cgconf); __wt_free(session, sourceconf); __wt_free(session, oldconf); __wt_buf_free(session, &confbuf); __wt_buf_free(session, &fmt); __wt_buf_free(session, &namebuf); __wt_schema_release_table(session, table); return (ret); }
/* * __create_index -- * Create an index. */ static int __create_index(WT_SESSION_IMPL *session, const char *name, int exclusive, const char *config) { WT_CONFIG kcols, pkcols; WT_CONFIG_ITEM ckey, cval, icols, kval; WT_DECL_PACK_VALUE(pv); WT_DECL_RET; WT_ITEM confbuf, extra_cols, fmt, namebuf; WT_PACK pack; WT_TABLE *table; const char *cfg[4] = { WT_CONFIG_BASE(session, index_meta), NULL, NULL, NULL }; const char *sourcecfg[] = { config, NULL, NULL }; const char *source, *sourceconf, *idxname, *tablename; char *idxconf; size_t tlen; int have_extractor; u_int i, npublic_cols; sourceconf = NULL; idxconf = NULL; WT_CLEAR(confbuf); WT_CLEAR(fmt); WT_CLEAR(extra_cols); WT_CLEAR(namebuf); have_extractor = 0; tablename = name; if (!WT_PREFIX_SKIP(tablename, "index:")) return (EINVAL); idxname = strchr(tablename, ':'); if (idxname == NULL) WT_RET_MSG(session, EINVAL, "Invalid index name, " "should be <table name>:<index name>: %s", name); tlen = (size_t)(idxname++ - tablename); if ((ret = __wt_schema_get_table(session, tablename, tlen, 1, &table)) != 0) WT_RET_MSG(session, ret, "Can't create an index for a non-existent table: %.*s", (int)tlen, tablename); if (table->is_simple) WT_RET_MSG(session, EINVAL, "%s requires a table with named columns", name); if (__wt_config_getones(session, config, "source", &cval) == 0) { WT_ERR(__wt_buf_fmt(session, &namebuf, "%.*s", (int)cval.len, cval.str)); source = namebuf.data; } else { WT_ERR(__wt_schema_index_source( session, table, idxname, config, &namebuf)); source = namebuf.data; /* Add the source name to the index config before collapsing. */ WT_ERR(__wt_buf_catfmt(session, &confbuf, ",source=\"%s\"", source)); } if (__wt_config_getones_none( session, config, "extractor", &cval) == 0 && cval.len != 0) { have_extractor = 1; /* Custom extractors must supply a key format. */ if ((ret = __wt_config_getones( session, config, "key_format", &kval)) != 0) WT_ERR_MSG(session, EINVAL, "%s: custom extractors require a key_format", name); } /* Calculate the key/value formats. */ WT_CLEAR(icols); if (__wt_config_getones(session, config, "columns", &icols) != 0 && !have_extractor) WT_ERR_MSG(session, EINVAL, "%s: requires 'columns' configuration", name); /* * Count the public columns using the declared columns for normal * indices or the key format for custom extractors. */ npublic_cols = 0; if (!have_extractor) { WT_ERR(__wt_config_subinit(session, &kcols, &icols)); while ((ret = __wt_config_next(&kcols, &ckey, &cval)) == 0) ++npublic_cols; WT_ERR_NOTFOUND_OK(ret); } else { WT_ERR(__pack_initn(session, &pack, kval.str, kval.len)); while ((ret = __pack_next(&pack, &pv)) == 0) ++npublic_cols; WT_ERR_NOTFOUND_OK(ret); } /* * The key format for an index is somewhat subtle: the application * specifies a set of columns that it will use for the key, but the * engine usually adds some hidden columns in order to derive the * primary key. These hidden columns are part of the source's * key_format, which we are calculating now, but not part of an index * cursor's key_format. */ WT_ERR(__wt_config_subinit(session, &pkcols, &table->colconf)); for (i = 0; i < table->nkey_columns && (ret = __wt_config_next(&pkcols, &ckey, &cval)) == 0; i++) { /* * If the primary key column is already in the secondary key, * don't add it again. */ if (__wt_config_subgetraw(session, &icols, &ckey, &cval) == 0) { if (have_extractor) WT_ERR_MSG(session, EINVAL, "an index with a custom extractor may not " "include primary key columns"); continue; } WT_ERR(__wt_buf_catfmt( session, &extra_cols, "%.*s,", (int)ckey.len, ckey.str)); } if (ret != 0 && ret != WT_NOTFOUND) goto err; /* Index values are empty: all columns are packed into the index key. */ WT_ERR(__wt_buf_fmt(session, &fmt, "value_format=,key_format=")); if (have_extractor) { WT_ERR(__wt_buf_catfmt(session, &fmt, "%.*s", (int)kval.len, kval.str)); WT_CLEAR(icols); } /* * Construct the index key format, or append the primary key columns * for custom extractors. */ WT_ERR(__wt_struct_reformat(session, table, icols.str, icols.len, (const char *)extra_cols.data, 0, &fmt)); /* Check for a record number index key, which makes no sense. */ WT_ERR(__wt_config_getones(session, fmt.data, "key_format", &cval)); if (cval.len == 1 && cval.str[0] == 'r') WT_ERR_MSG(session, EINVAL, "column-store index may not use the record number as its " "index key"); WT_ERR(__wt_buf_catfmt( session, &fmt, ",index_key_columns=%u", npublic_cols)); sourcecfg[1] = fmt.data; WT_ERR(__wt_config_merge(session, sourcecfg, NULL, &sourceconf)); WT_ERR(__wt_schema_create(session, source, sourceconf)); cfg[1] = sourceconf; cfg[2] = confbuf.data; WT_ERR(__wt_config_collapse(session, cfg, &idxconf)); if ((ret = __wt_metadata_insert(session, name, idxconf)) != 0) { /* * If the entry already exists in the metadata, we're done. * This is an error for exclusive creates but okay otherwise. */ if (ret == WT_DUPLICATE_KEY) ret = exclusive ? EEXIST : 0; goto err; } /* Make sure that the configuration is valid. */ WT_ERR(__wt_schema_open_index( session, table, idxname, strlen(idxname), NULL)); err: __wt_free(session, idxconf); __wt_free(session, sourceconf); __wt_buf_free(session, &confbuf); __wt_buf_free(session, &extra_cols); __wt_buf_free(session, &fmt); __wt_buf_free(session, &namebuf); __wt_schema_release_table(session, table); return (ret); }
/* * __create_file -- * Create a new 'file:' object. */ static int __create_file(WT_SESSION_IMPL *session, const char *uri, int exclusive, const char *config) { WT_DECL_ITEM(val); WT_DECL_RET; uint32_t allocsize; int is_metadata; const char *filename, **p, *filecfg[] = { WT_CONFIG_BASE(session, file_meta), config, NULL, NULL }; char *fileconf; fileconf = NULL; is_metadata = strcmp(uri, WT_METAFILE_URI) == 0; filename = uri; if (!WT_PREFIX_SKIP(filename, "file:")) WT_RET_MSG(session, EINVAL, "Expected a 'file:' URI: %s", uri); /* Check if the file already exists. */ if (!is_metadata && (ret = __wt_metadata_search(session, uri, &fileconf)) != WT_NOTFOUND) { if (exclusive) WT_TRET(EEXIST); goto err; } /* Sanity check the allocation size. */ WT_RET(__wt_direct_io_size_check( session, filecfg, "allocation_size", &allocsize)); /* Create the file. */ WT_ERR(__wt_block_manager_create(session, filename, allocsize)); if (WT_META_TRACKING(session)) WT_ERR(__wt_meta_track_fileop(session, NULL, uri)); /* * If creating an ordinary file, append the file ID and current version * numbers to the passed-in configuration and insert the resulting * configuration into the metadata. */ if (!is_metadata) { WT_ERR(__wt_scr_alloc(session, 0, &val)); WT_ERR(__wt_buf_fmt(session, val, "id=%" PRIu32 ",version=(major=%d,minor=%d)", ++S2C(session)->next_file_id, WT_BTREE_MAJOR_VERSION_MAX, WT_BTREE_MINOR_VERSION_MAX)); for (p = filecfg; *p != NULL; ++p) ; *p = val->data; WT_ERR(__wt_config_collapse(session, filecfg, &fileconf)); WT_ERR(__wt_metadata_insert(session, uri, fileconf)); } /* * Open the file to check that it was setup correctly. We don't need to * pass the configuration, we just wrote the collapsed configuration * into the metadata file, and it's going to be read/used by underlying * functions. * * Keep the handle exclusive until it is released at the end of the * call, otherwise we could race with a drop. */ WT_ERR(__wt_session_get_btree( session, uri, NULL, NULL, WT_DHANDLE_EXCLUSIVE)); if (WT_META_TRACKING(session)) WT_ERR(__wt_meta_track_handle_lock(session, 1)); else WT_ERR(__wt_session_release_btree(session)); err: __wt_scr_free(session, &val); __wt_free(session, fileconf); return (ret); }
/* * __create_table -- * Create a table. */ static int __create_table(WT_SESSION_IMPL *session, const char *name, int exclusive, const char *config) { WT_CONFIG conf; WT_CONFIG_ITEM cgkey, cgval, cval; WT_DECL_RET; WT_TABLE *table; const char *cfg[4] = { WT_CONFIG_BASE(session, table_meta), config, NULL, NULL }; const char *tablename; char *tableconf, *cgname; size_t cgsize; int ncolgroups; cgname = NULL; table = NULL; tableconf = NULL; tablename = name; if (!WT_PREFIX_SKIP(tablename, "table:")) return (EINVAL); if ((ret = __wt_schema_get_table(session, tablename, strlen(tablename), 0, &table)) == 0) { __wt_schema_release_table(session, table); return (exclusive ? EEXIST : 0); } WT_RET_NOTFOUND_OK(ret); WT_ERR(__wt_config_gets(session, cfg, "colgroups", &cval)); WT_ERR(__wt_config_subinit(session, &conf, &cval)); for (ncolgroups = 0; (ret = __wt_config_next(&conf, &cgkey, &cgval)) == 0; ncolgroups++) ; WT_ERR_NOTFOUND_OK(ret); WT_ERR(__wt_config_collapse(session, cfg, &tableconf)); if ((ret = __wt_metadata_insert(session, name, tableconf)) != 0) { /* * If the entry already exists in the metadata, we're done. * This is an error for exclusive creates but okay otherwise. */ if (ret == WT_DUPLICATE_KEY) ret = exclusive ? EEXIST : 0; goto err; } /* Attempt to open the table now to catch any errors. */ WT_ERR(__wt_schema_get_table( session, tablename, strlen(tablename), 1, &table)); if (ncolgroups == 0) { cgsize = strlen("colgroup:") + strlen(tablename) + 1; WT_ERR(__wt_calloc_def(session, cgsize, &cgname)); snprintf(cgname, cgsize, "colgroup:%s", tablename); WT_ERR(__create_colgroup(session, cgname, exclusive, config)); } if (0) { err: if (table != NULL) { WT_TRET(__wt_schema_remove_table(session, table)); table = NULL; } } if (table != NULL) __wt_schema_release_table(session, table); __wt_free(session, cgname); __wt_free(session, tableconf); return (ret); }