📄 fs.c
字号:
/* If log files do not match, go to the next log filr. */ if (files_match == FALSE) continue; } SVN_ERR(svn_io_remove_file(live_log_path, sub_pool)); } svn_pool_destroy(sub_pool); } return SVN_NO_ERROR;}/* ### There -must- be a more elegant way to do a compile-time check for BDB 4.2 or later. We're doing this because apparently env->get_flags() and DB->get_pagesize() don't exist in earlier versions of BDB. */#ifdef DB_LOG_AUTOREMOVE/* Open the BDB environment at PATH and compare its configuration flags with FLAGS. If every flag in FLAGS is set in the environment, then set *MATCH to true. Else set *MATCH to false. */static svn_error_t *check_env_flags(svn_boolean_t *match, u_int32_t flags, const char *path, apr_pool_t *pool){ bdb_env_baton_t *bdb; u_int32_t envflags; SVN_ERR(svn_fs_bdb__open(&bdb, path, SVN_BDB_STANDARD_ENV_FLAGS, 0666, pool)); SVN_BDB_ERR(bdb, bdb->env->get_flags(bdb->env, &envflags)); SVN_ERR(svn_fs_bdb__close(bdb)); if (flags & envflags) *match = TRUE; else *match = FALSE; return SVN_NO_ERROR;}/* Set *PAGESIZE to the size of pages used to hold items in the database environment located at PATH.*/static svn_error_t *get_db_pagesize(u_int32_t *pagesize, const char *path, apr_pool_t *pool){ bdb_env_baton_t *bdb; DB *nodes_table; SVN_ERR(svn_fs_bdb__open(&bdb, path, SVN_BDB_STANDARD_ENV_FLAGS, 0666, pool)); /* ### We're only asking for the pagesize on the 'nodes' table. Is this enough? We never call DB->set_pagesize() on any of our tables, so presumably BDB is using the same default pagesize for all our databases, right? */ SVN_BDB_ERR(bdb, svn_fs_bdb__open_nodes_table(&nodes_table, bdb->env, FALSE)); SVN_BDB_ERR(bdb, nodes_table->get_pagesize(nodes_table, pagesize)); SVN_BDB_ERR(bdb, nodes_table->close(nodes_table, 0)); return svn_fs_bdb__close(bdb);}#endif /* DB_LOG_AUTOREMOVE *//* Copy FILENAME from SRC_DIR to DST_DIR in byte increments of size CHUNKSIZE. The read/write buffer of size CHUNKSIZE will be allocated in POOL. */static svn_error_t *copy_db_file_safely(const char *src_dir, const char *dst_dir, const char *filename, u_int32_t chunksize, apr_pool_t *pool){ apr_file_t *s = NULL, *d = NULL; /* init to null important for APR */ const char *file_src_path = svn_path_join(src_dir, filename, pool); const char *file_dst_path = svn_path_join(dst_dir, filename, pool); char *buf; /* Open source file. */ SVN_ERR(svn_io_file_open(&s, file_src_path, (APR_READ | APR_LARGEFILE | APR_BINARY), APR_OS_DEFAULT, pool)); /* Open destination file. */ SVN_ERR(svn_io_file_open(&d, file_dst_path, (APR_WRITE | APR_CREATE | APR_LARGEFILE | APR_BINARY), APR_OS_DEFAULT, pool)); /* Allocate our read/write buffer. */ buf = apr_palloc(pool, chunksize); /* Copy bytes till the cows come home. */ while (1) { apr_size_t bytes_this_time = chunksize; svn_error_t *read_err, *write_err; /* Read 'em. */ if ((read_err = svn_io_file_read(s, buf, &bytes_this_time, pool))) { if (APR_STATUS_IS_EOF(read_err->apr_err)) svn_error_clear(read_err); else { svn_error_clear(svn_io_file_close(s, pool)); svn_error_clear(svn_io_file_close(d, pool)); return read_err; } } /* Write 'em. */ if ((write_err = svn_io_file_write_full(d, buf, bytes_this_time, NULL, pool))) { svn_error_clear(svn_io_file_close(s, pool)); svn_error_clear(svn_io_file_close(d, pool)); return write_err; } /* read_err is either NULL, or a dangling pointer - but it is only a dangling pointer if it used to be an EOF error. */ if (read_err) { SVN_ERR(svn_io_file_close(s, pool)); SVN_ERR(svn_io_file_close(d, pool)); break; /* got EOF on read, all files closed, all done. */ } } return SVN_NO_ERROR;}static svn_error_t *base_hotcopy(const char *src_path, const char *dest_path, svn_boolean_t clean_logs, apr_pool_t *pool){ svn_error_t *err; u_int32_t pagesize; svn_boolean_t log_autoremove = FALSE; int format; /* Check the FS format number to be certain that we know how to hotcopy this FS. Pre-1.2 filesystems did not have a format file (you could say they were format "0"), so we will error here. This is not optimal, but since this has been the case since 1.2.0, and no one has complained, it apparently isn't much of a concern. (We did not check the 'format' file in 1.2.x, but we did blindly try to copy 'locks', which would have errored just the same.) */ SVN_ERR(svn_io_read_version_file (&format, svn_path_join(src_path, FORMAT_FILE, pool), pool)); SVN_ERR(check_format(format)); /* If using DB 4.2 or later, note whether the DB_LOG_AUTOREMOVE feature is on. If it is, we have a potential race condition: another process might delete a logfile while we're in the middle of copying all the logfiles. (This is not a huge deal; at worst, the hotcopy fails with a file-not-found error.) */#ifdef DB_LOG_AUTOREMOVE SVN_ERR(check_env_flags(&log_autoremove, DB_LOG_AUTOREMOVE, src_path, pool));#endif /* Copy the DB_CONFIG file. */ SVN_ERR(svn_io_dir_file_copy(src_path, dest_path, "DB_CONFIG", pool)); /* In order to copy the database files safely and atomically, we must copy them in chunks which are multiples of the page-size used by BDB. See sleepycat docs for details, or svn issue #1818. */#ifdef DB_LOG_AUTOREMOVE SVN_ERR(get_db_pagesize(&pagesize, src_path, pool)); if (pagesize < SVN__STREAM_CHUNK_SIZE) { /* use the largest multiple of BDB pagesize we can. */ int multiple = SVN__STREAM_CHUNK_SIZE / pagesize; pagesize *= multiple; }#else /* default to 128K chunks, which should be safe. BDB almost certainly uses a power-of-2 pagesize. */ pagesize = (4096 * 32); #endif /* Copy the databases. */ SVN_ERR(copy_db_file_safely(src_path, dest_path, "nodes", pagesize, pool)); SVN_ERR(copy_db_file_safely(src_path, dest_path, "transactions", pagesize, pool)); SVN_ERR(copy_db_file_safely(src_path, dest_path, "revisions", pagesize, pool)); SVN_ERR(copy_db_file_safely(src_path, dest_path, "copies", pagesize, pool)); SVN_ERR(copy_db_file_safely(src_path, dest_path, "changes", pagesize, pool)); SVN_ERR(copy_db_file_safely(src_path, dest_path, "representations", pagesize, pool)); SVN_ERR(copy_db_file_safely(src_path, dest_path, "strings", pagesize, pool)); SVN_ERR(copy_db_file_safely(src_path, dest_path, "uuids", pagesize, pool)); SVN_ERR(copy_db_file_safely(src_path, dest_path, "locks", pagesize, pool)); SVN_ERR(copy_db_file_safely(src_path, dest_path, "lock-tokens", pagesize, pool)); { apr_array_header_t *logfiles; int idx; apr_pool_t *subpool; SVN_ERR(base_bdb_logfiles(&logfiles, src_path, FALSE, /* All logs */ pool)); /* Process log files. */ subpool = svn_pool_create(pool); for (idx = 0; idx < logfiles->nelts; idx++) { svn_pool_clear(subpool); err = svn_io_dir_file_copy(src_path, dest_path, APR_ARRAY_IDX(logfiles, idx, const char *), subpool); if (err) { if (log_autoremove) return svn_error_quick_wrap (err, _("Error copying logfile; the DB_LOG_AUTOREMOVE feature \n" "may be interfering with the hotcopy algorithm. If \n" "the problem persists, try deactivating this feature \n" "in DB_CONFIG")); else return err; } } svn_pool_destroy(subpool); } /* Since this is a copy we will have exclusive access to the repository. */ err = bdb_recover(dest_path, TRUE, pool); if (err) { if (log_autoremove) return svn_error_quick_wrap (err, _("Error running catastrophic recovery on hotcopy; the \n" "DB_LOG_AUTOREMOVE feature may be interfering with the \n" "hotcopy algorithm. If the problem persists, try deactivating \n" "this feature in DB_CONFIG")); else return err; } /* Only now that the hotcopied filesystem is complete, stamp it with a format file. */ SVN_ERR(svn_io_write_version_file (svn_path_join(dest_path, FORMAT_FILE, pool), format, pool)); if (clean_logs == TRUE) SVN_ERR(svn_fs_base__clean_logs(src_path, dest_path, pool)); return SVN_NO_ERROR;}/* Deleting a Berkeley DB-based filesystem. */static svn_error_t *base_delete_fs(const char *path, apr_pool_t *pool){ /* First, use the Berkeley DB library function to remove any shared memory segments. */ SVN_ERR(svn_fs_bdb__remove(path, pool)); /* Remove the environment directory. */ SVN_ERR(svn_io_remove_dir(path, pool)); return SVN_NO_ERROR;}/* Miscellany */const char *svn_fs_base__canonicalize_abspath(const char *path, apr_pool_t *pool){ char *newpath; int path_len; int path_i = 0, newpath_i = 0; svn_boolean_t eating_slashes = FALSE; /* No PATH? No problem. */ if (! path) return NULL; /* Empty PATH? That's just "/". */ if (! *path) return apr_pstrdup(pool, "/"); /* Now, the fun begins. Alloc enough room to hold PATH with an added leading '/'. */ path_len = strlen(path); newpath = apr_pcalloc(pool, path_len + 2); /* No leading slash? Fix that. */ if (*path != '/') { newpath[newpath_i++] = '/'; } for (path_i = 0; path_i < path_len; path_i++) { if (path[path_i] == '/') { /* The current character is a '/'. If we are eating up extra '/' characters, skip this character. Else, note that we are now eating slashes. */ if (eating_slashes) continue; eating_slashes = TRUE; } else { /* The current character is NOT a '/'. If we were eating slashes, we need not do that any more. */ if (eating_slashes) eating_slashes = FALSE; } /* Copy the current character into our new buffer. */ newpath[newpath_i++] = path[path_i]; } /* Did we leave a '/' attached to the end of NEWPATH (other than in the root directory case)? */ if ((newpath[newpath_i - 1] == '/') && (newpath_i > 1)) newpath[newpath_i - 1] = '\0'; return newpath;}static const svn_version_t *base_version(void){ SVN_VERSION_BODY;}static const char *base_get_description(void){ return _("Module for working with a Berkeley DB repository.");}/* Base FS library vtable, used by the FS loader library. */static fs_library_vtable_t library_vtable = { base_version, base_create, base_open, base_delete_fs, base_hotcopy, base_get_description, base_bdb_recover, base_bdb_logfiles, svn_fs_base__id_parse};svn_error_t *svn_fs_base__init(const svn_version_t *loader_version, fs_library_vtable_t **vtable){ static const svn_version_checklist_t checklist[] = { { "svn_subr", svn_subr_version }, { "svn_delta", svn_delta_version }, { NULL, NULL } }; /* Simplified version check to make sure we can safely use the VTABLE parameter. The FS loader does a more exhaustive check. */ if (loader_version->major != SVN_VER_MAJOR) return svn_error_createf(SVN_ERR_VERSION_MISMATCH, NULL, _("Unsupported FS loader version (%d) for bdb"), loader_version->major); SVN_ERR(svn_ver_check_list(base_version(), checklist)); SVN_ERR(check_bdb_version()); SVN_ERR(svn_fs_bdb__init()); *vtable = &library_vtable; return SVN_NO_ERROR;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -