svn_error_t * svn_sqlite__hotcopy(const char *src_path, const char *dst_path, apr_pool_t *scratch_pool) { svn_sqlite__db_t *src_db; SVN_ERR(svn_sqlite__open(&src_db, src_path, svn_sqlite__mode_readonly, NULL, 0, NULL, 0, scratch_pool, scratch_pool)); { svn_sqlite__db_t *dst_db; sqlite3_backup *backup; int rc1, rc2; SVN_ERR(svn_sqlite__open(&dst_db, dst_path, svn_sqlite__mode_rwcreate, NULL, 0, NULL, 0, scratch_pool, scratch_pool)); backup = sqlite3_backup_init(dst_db->db3, "main", src_db->db3, "main"); if (!backup) return svn_error_createf(SVN_ERR_SQLITE_ERROR, NULL, _("SQLite hotcopy failed for %s"), src_path); do { /* Pages are usually 1024 byte (SQLite docs). On my laptop copying gets faster as the number of pages is increased up to about 64, beyond that speed levels off. Lets put the number of pages an order of magnitude higher, this is still likely to be a fraction of large databases. */ rc1 = sqlite3_backup_step(backup, 1024); /* Should we sleep on SQLITE_OK? That would make copying a large database take much longer. When we do sleep how, long should we sleep? Should the sleep get longer if we keep getting BUSY/LOCKED? I have no real reason for choosing 25. */ if (rc1 == SQLITE_BUSY || rc1 == SQLITE_LOCKED) sqlite3_sleep(25); } while (rc1 == SQLITE_OK || rc1 == SQLITE_BUSY || rc1 == SQLITE_LOCKED); rc2 = sqlite3_backup_finish(backup); if (rc1 != SQLITE_DONE) SQLITE_ERR(rc1, dst_db); SQLITE_ERR(rc2, dst_db); SVN_ERR(svn_sqlite__close(dst_db)); } SVN_ERR(svn_sqlite__close(src_db)); SVN_ERR(svn_io_copy_perms(src_path, dst_path, scratch_pool)); return SVN_NO_ERROR; }
/* Body of svn_fs_fs__open_rep_cache(). Implements svn_atomic__init_once().init_func. */ static svn_error_t * open_rep_cache(void *baton, apr_pool_t *pool) { svn_fs_t *fs = baton; fs_fs_data_t *ffd = fs->fsap_data; const char *db_path; int version; /* Open (or create) the sqlite database. It will be automatically closed when fs->pool is destoyed. */ db_path = path_rep_cache_db(fs->path, pool); SVN_ERR(svn_sqlite__open(&ffd->rep_cache_db, db_path, svn_sqlite__mode_rwcreate, statements, 0, NULL, fs->pool, pool)); SVN_ERR(svn_sqlite__read_schema_version(&version, ffd->rep_cache_db, pool)); if (version < REP_CACHE_SCHEMA_FORMAT) { /* Must be 0 -- an uninitialized (no schema) database. Create the schema. Results in schema version of 1. */ SVN_ERR(svn_sqlite__exec_statements(ffd->rep_cache_db, STMT_CREATE_SCHEMA)); } return SVN_NO_ERROR; }
/* Body of svn_fs_fs__open_rep_cache(). Implements svn_atomic__init_once().init_func. */ static svn_error_t * open_rep_cache(void *baton, apr_pool_t *pool) { svn_fs_t *fs = baton; fs_fs_data_t *ffd = fs->fsap_data; svn_sqlite__db_t *sdb; const char *db_path; int version; /* Open (or create) the sqlite database. It will be automatically closed when fs->pool is destroyed. */ db_path = path_rep_cache_db(fs->path, pool); #ifndef WIN32 { /* We want to extend the permissions that apply to the repository as a whole when creating a new rep cache and not simply default to umask. */ svn_boolean_t exists; SVN_ERR(svn_fs_fs__exists_rep_cache(&exists, fs, pool)); if (!exists) { const char *current = svn_fs_fs__path_current(fs, pool); svn_error_t *err = svn_io_file_create_empty(db_path, pool); if (err && !APR_STATUS_IS_EEXIST(err->apr_err)) /* A real error. */ return svn_error_trace(err); else if (err) /* Some other thread/process created the file. */ svn_error_clear(err); else /* We created the file. */ SVN_ERR(svn_io_copy_perms(current, db_path, pool)); } } #endif SVN_ERR(svn_sqlite__open(&sdb, db_path, svn_sqlite__mode_rwcreate, statements, 0, NULL, 0, fs->pool, pool)); SVN_ERR_CLOSE(svn_sqlite__read_schema_version(&version, sdb, pool), sdb); if (version < REP_CACHE_SCHEMA_FORMAT) { /* Must be 0 -- an uninitialized (no schema) database. Create the schema. Results in schema version of 1. */ SVN_ERR_CLOSE(svn_sqlite__exec_statements(sdb, STMT_CREATE_SCHEMA), sdb); } /* This is used as a flag that the database is available so don't set it earlier. */ ffd->rep_cache_db = sdb; return SVN_NO_ERROR; }
svn_error_t * svn_wc__db_util_open_db(svn_sqlite__db_t **sdb, const char *dir_abspath, const char *sdb_fname, svn_sqlite__mode_t smode, svn_boolean_t exclusive, const char *const *my_statements, apr_pool_t *result_pool, apr_pool_t *scratch_pool) { const char *sdb_abspath = svn_wc__adm_child(dir_abspath, sdb_fname, scratch_pool); if (smode != svn_sqlite__mode_rwcreate) { svn_node_kind_t kind; /* A file stat is much cheaper then a failed database open handled by SQLite. */ SVN_ERR(svn_io_check_path(sdb_abspath, &kind, scratch_pool)); if (kind != svn_node_file) return svn_error_createf(APR_ENOENT, NULL, _("Working copy database '%s' not found"), svn_dirent_local_style(sdb_abspath, scratch_pool)); } #ifndef WIN32 else { apr_file_t *f; /* A standard SQLite build creates a DB with mode 644 ^ !umask which means the file doesn't have group/world write access even when umask allows it. By ensuring the file exists before SQLite gets involved we give it the permissions allowed by umask. */ SVN_ERR(svn_io_file_open(&f, sdb_abspath, (APR_READ | APR_WRITE | APR_CREATE), APR_OS_DEFAULT, scratch_pool)); SVN_ERR(svn_io_file_close(f, scratch_pool)); } #endif SVN_ERR(svn_sqlite__open(sdb, sdb_abspath, smode, my_statements ? my_statements : statements, 0, NULL, result_pool, scratch_pool)); if (exclusive) SVN_ERR(svn_sqlite__exec_statements(*sdb, STMT_PRAGMA_LOCKING_MODE)); SVN_ERR(svn_sqlite__create_scalar_function(*sdb, "relpath_depth", 1, relpath_depth_sqlite, NULL)); return SVN_NO_ERROR; }
svn_error_t * svn_wc__db_util_open_db(svn_sqlite__db_t **sdb, const char *dir_abspath, const char *sdb_fname, svn_sqlite__mode_t smode, svn_boolean_t exclusive, apr_int32_t timeout, const char *const *my_statements, apr_pool_t *result_pool, apr_pool_t *scratch_pool) { const char *sdb_abspath = svn_wc__adm_child(dir_abspath, sdb_fname, scratch_pool); if (smode != svn_sqlite__mode_rwcreate) { svn_node_kind_t kind; /* A file stat is much cheaper than a failed database open handled by SQLite. */ SVN_ERR(svn_io_check_path(sdb_abspath, &kind, scratch_pool)); if (kind != svn_node_file) return svn_error_createf(APR_ENOENT, NULL, _("Working copy database '%s' not found"), svn_dirent_local_style(sdb_abspath, scratch_pool)); } SVN_ERR(svn_sqlite__open(sdb, sdb_abspath, smode, my_statements ? my_statements : statements, 0, NULL, timeout, result_pool, scratch_pool)); if (exclusive) SVN_ERR(svn_sqlite__exec_statements(*sdb, STMT_PRAGMA_LOCKING_MODE)); SVN_ERR(svn_sqlite__create_scalar_function(*sdb, "relpath_depth", 1, TRUE /* deterministic */, relpath_depth_sqlite, NULL)); return SVN_NO_ERROR; }
svn_error_t * svn_wc__db_util_open_db(svn_sqlite__db_t **sdb, const char *dir_abspath, const char *sdb_fname, svn_sqlite__mode_t smode, const char *const *my_statements, apr_pool_t *result_pool, apr_pool_t *scratch_pool) { const char *sdb_abspath = svn_wc__adm_child(dir_abspath, sdb_fname, scratch_pool); if (smode != svn_sqlite__mode_rwcreate) { svn_node_kind_t kind; /* A file stat is much cheaper then a failed database open handled by SQLite. */ SVN_ERR(svn_io_check_path(sdb_abspath, &kind, scratch_pool)); if (kind != svn_node_file) return svn_error_createf(APR_ENOENT, NULL, _("Working copy database '%s' not found"), svn_dirent_local_style(sdb_abspath, scratch_pool)); } SVN_ERR(svn_sqlite__open(sdb, sdb_abspath, smode, my_statements ? my_statements : statements, 0, NULL, result_pool, scratch_pool)); SVN_ERR(svn_sqlite__create_scalar_function(*sdb, "relpath_depth", 1, relpath_depth, NULL)); return SVN_NO_ERROR; }