Author: rhuijben
Date: Mon Jul 5 16:40:31 2010
New Revision: 960635
URL: http://svn.apache.org/viewvc?rev=960635&view=rev
Log:
To allow improving the svn status performance, allow retrieving the size
and mtime of files directly when retrieving the dirents inside a directory.
Performing a stat of every file individually will never be as fast as per
directory. Especially if we open the directory for reading anyway.
* subversion/include/svn_io.h
(svn_io_dirent2_t): New struct.
(svn_io_dirent2_create): New function.
(svn_io_dirent2_dup): New function.
(svn_io_dirent_t): Update documentation.
(svn_io_get_dirents3): New function.
(svn_io_get_dirents2): Deprecate function.
(svn_io_stat_dirent): New function. (Helper for wc status walker)
* subversion/libsvn_subr/deprecated.c
(svn_io_get_dirents2): New function.
(svn_io_get_dirents): Move function here from io.c
* subversion/libsvn_subr/io.c
(svn_io_remove_dir2): Use svn_io_get_dirents3 and avoid casts.
(svn_io_dirent2_create): New function.
(svn_io_dirent2_dup): New function.
(svn_io_get_dirents2): Rename to ...
(svn_io_get_dirents3): ... this, update struct for hash. Retrieve
additional values only if required.
Modified:
subversion/trunk/subversion/include/svn_io.h
subversion/trunk/subversion/libsvn_subr/deprecated.c
subversion/trunk/subversion/libsvn_subr/io.c
Modified: subversion/trunk/subversion/include/svn_io.h
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/include/svn_io.h?rev=960635&r1=960634&r2=960635&view=diff
==============================================================================
--- subversion/trunk/subversion/include/svn_io.h (original)
+++ subversion/trunk/subversion/include/svn_io.h Mon Jul 5 16:40:31 2010
@@ -65,10 +65,59 @@ typedef enum svn_io_file_del_t
svn_io_file_del_on_pool_cleanup
} svn_io_file_del_t;
+/** A set of directory entry data elements as returned by svn_io_get_dirents
+ *
+ * Note that the first two fields are exactly identical to svn_io_dirent_t
+ * to allow returning a svn_io_dirent2_t as a svn_io_dirent_t.
+ *
+ * Use svn_io_dirent2_create() to create new svn_dirent2_t instances or
+ * svn_io_dirent2_dup() to duplicate an existing instance.
+ *
+ * @since New in 1.7.
+ */
+typedef struct svn_io_dirent2_t {
+ /* New fields must be added at the end to preserve binary compatibility */
+
+ /** The kind of this entry. */
+ svn_node_kind_t kind;
+
+ /** If @c kind is #svn_node_file, whether this entry is a special file;
+ * else FALSE.
+ *
+ * @see svn_io_check_special_path().
+ */
+ svn_boolean_t special;
+
+ /** The filesize of this entry or undefined for a directory */
+ svn_filesize_t filesize;
+
+ /** The time the file was last modified */
+ apr_time_t mtime;
+
+ /* Don't forget to update svn_io_dirent2_dup() when adding new fields */
+} svn_io_dirent2_t;
+
+
+/** Creates a new @a svn_io_dirent2_t structure
+ *
+ * @since New in 1.7.
+ */
+svn_io_dirent2_t *
+svn_io_dirent2_create(apr_pool_t *result_pool);
+
+/** Duplicates a @c svn_io_dirent2_t structure into @a result_pool.
+ *
+ * @since New in 1.7.
+ */
+svn_io_dirent2_t *
+svn_io_dirent2_dup(const svn_io_dirent2_t *item,
+ apr_pool_t *result_pool);
-
/** Represents the kind and special status of a directory entry.
*
+ * Note that the first two fields are exactly identical to svn_io_dirent2_t
+ * to allow returning a svn_io_dirent2_t as a svn_io_dirent_t.
+ *
* @since New in 1.3.
*/
typedef struct svn_io_dirent_t {
@@ -1396,16 +1445,33 @@ svn_io_get_dir_filenames(apr_hash_t **di
/** Read all of the disk entries in directory @a path, a utf8-encoded
* path. Set @a *dirents to a hash mapping dirent names (<tt>char *</tt>) to
- * #svn_io_dirent_t structures, allocated in @a pool.
+ * #svn_io_dirent2_t structures, allocated in @a pool.
+ *
+ * If @a only_check_type is set to @c TRUE, only the kind and special
+ * fields of the svn_io_dirent2_t are filled.
*
* @note The `.' and `..' directories normally returned by
* apr_dir_read() are NOT returned in the hash.
*
* @note The kind field in the @a dirents is set according to the mapping
- * as documented for svn_io_check_path()
+ * as documented for svn_io_check_path().
+ *
+ * @since New in 1.7.
+ */
+svn_error_t *
+svn_io_get_dirents3(apr_hash_t **dirents,
+ const char *path,
+ svn_boolean_t only_check_type,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool);
+
+
+/** Similar to svn_io_get_dirents3, but returns a mapping to svn_io_dirent_t
+ * structures instead of svn_io_dirent2_t and with only a single pool.
*
* @since New in 1.3.
*/
+SVN_DEPRECATED
svn_error_t *
svn_io_get_dirents2(apr_hash_t **dirents,
const char *path,
@@ -1422,6 +1488,17 @@ svn_io_get_dirents(apr_hash_t **dirents,
const char *path,
apr_pool_t *pool);
+/** Create a svn_io_dirent2_t instance for path. Specialized variant of
+ * svn_io_stat() that directly translates node_kind and special.
+ *
+ * @since New in 1.7.
+ */
+static svn_error_t *
+svn_io_stat_dirent(const svn_io_dirent2_t **dirent_p,
+ const char *path,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool);
+
/** Callback function type for svn_io_dir_walk() */
typedef svn_error_t * (*svn_io_walk_func_t)(void *baton,
Modified: subversion/trunk/subversion/libsvn_subr/deprecated.c
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_subr/deprecated.c?rev=960635&r1=960634&r2=960635&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_subr/deprecated.c (original)
+++ subversion/trunk/subversion/libsvn_subr/deprecated.c Mon Jul 5 16:40:31
2010
@@ -729,6 +729,28 @@ svn_error_t *svn_io_file_lock(const char
return svn_io_file_lock2(lock_file, exclusive, FALSE, pool);
}
+svn_error_t *
+svn_io_get_dirents2(apr_hash_t **dirents,
+ const char *path,
+ apr_pool_t *pool)
+{
+ /* Note that the first part of svn_io_dirent2_t is identical
+ to svn_io_dirent_t to allow this construct */
+ return svn_error_return(
+ svn_io_get_dirents3(dirents, path, FALSE, pool, pool));
+}
+
+svn_error_t *
+svn_io_get_dirents(apr_hash_t **dirents,
+ const char *path,
+ apr_pool_t *pool)
+{
+ /* Note that in C, padding is not allowed at the beginning of structs,
+ so this is actually portable, since the kind field of svn_io_dirent_t
+ is first in that struct. */
+ return svn_io_get_dirents2(dirents, path, pool);
+}
+
/*** From constructors.c ***/
svn_log_changed_path_t *
Modified: subversion/trunk/subversion/libsvn_subr/io.c
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_subr/io.c?rev=960635&r1=960634&r2=960635&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_subr/io.c (original)
+++ subversion/trunk/subversion/libsvn_subr/io.c Mon Jul 5 16:40:31 2010
@@ -1918,7 +1918,7 @@ svn_io_remove_dir2(const char *path, svn
svn_error_t *err;
apr_pool_t *subpool;
apr_hash_t *dirents;
- apr_hash_index_t *ent;
+ apr_hash_index_t *hi;
/* Check for pending cancellation request.
If we need to bail out, do so early. */
@@ -1928,7 +1928,7 @@ svn_io_remove_dir2(const char *path, svn
subpool = svn_pool_create(pool);
- err = svn_io_get_dirents2(&dirents, path, subpool);
+ err = svn_io_get_dirents3(&dirents, path, TRUE, subpool, subpool);
if (err)
{
/* if the directory doesn't exist, our mission is accomplished */
@@ -1940,15 +1940,14 @@ svn_io_remove_dir2(const char *path, svn
return svn_error_return(err);
}
- for (ent = apr_hash_first(subpool, dirents); ent; ent = apr_hash_next(ent))
+ for (hi = apr_hash_first(subpool, dirents); hi; hi = apr_hash_next(hi))
{
- const void *key;
- void *val;
- char *fullpath;
-
- apr_hash_this(ent, &key, NULL, &val);
- fullpath = svn_dirent_join(path, key, subpool);
- if (((svn_io_dirent_t *)val)->kind == svn_node_dir)
+ const char *name = svn__apr_hash_index_key(hi);
+ const svn_io_dirent2_t *dirent = svn__apr_hash_index_val(hi);
+ const char *fullpath;
+
+ fullpath = svn_dirent_join(path, name, subpool);
+ if (dirent->kind == svn_node_dir)
{
/* Don't check for cancellation, the callee will immediately do so */
SVN_ERR(svn_io_remove_dir2(fullpath, FALSE, cancel_func,
@@ -2017,19 +2016,46 @@ svn_io_get_dir_filenames(apr_hash_t **di
return SVN_NO_ERROR;
}
+svn_io_dirent2_t *
+svn_io_dirent2_create(apr_pool_t *result_pool)
+{
+ svn_io_dirent2_t *dirent = apr_pcalloc(result_pool, sizeof(*dirent));
+
+ /*dirent->kind = svn_node_none;
+ dirent->special = FALSE;*/
+ dirent->filesize = SVN_INVALID_FILESIZE;
+ /*dirent->mtime = 0;*/
+
+ return dirent;
+}
+
+svn_io_dirent2_t *
+svn_io_dirent2_dup(const svn_io_dirent2_t *item,
+ apr_pool_t *result_pool)
+{
+ return apr_pmemdup(result_pool,
+ item,
+ sizeof(*item));
+}
+
svn_error_t *
-svn_io_get_dirents2(apr_hash_t **dirents,
+svn_io_get_dirents3(apr_hash_t **dirents,
const char *path,
- apr_pool_t *pool)
+ svn_boolean_t only_check_type,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
{
apr_status_t status;
apr_dir_t *this_dir;
apr_finfo_t this_entry;
apr_int32_t flags = APR_FINFO_TYPE | APR_FINFO_NAME;
- *dirents = apr_hash_make(pool);
+ if (!only_check_type)
+ flags |= APR_FINFO_SIZE | APR_FINFO_MTIME;
- SVN_ERR(svn_io_dir_open(&this_dir, path, pool));
+ *dirents = apr_hash_make(result_pool);
+
+ SVN_ERR(svn_io_dir_open(&this_dir, path, scratch_pool));
for (status = apr_dir_read(&this_entry, flags, this_dir);
status == APR_SUCCESS;
@@ -2045,39 +2071,59 @@ svn_io_get_dirents2(apr_hash_t **dirents
else
{
const char *name;
- svn_io_dirent_t *dirent = apr_palloc(pool, sizeof(*dirent));
+ svn_io_dirent2_t *dirent = svn_io_dirent2_create(result_pool);
- SVN_ERR(entry_name_to_utf8(&name, this_entry.name, path, pool));
+ SVN_ERR(entry_name_to_utf8(&name, this_entry.name, path,
result_pool));
map_apr_finfo_to_node_kind(&(dirent->kind),
&(dirent->special),
&this_entry);
+ if (!only_check_type)
+ {
+ dirent->filesize = this_entry.size;
+ dirent->mtime = this_entry.mtime;
+ }
+
apr_hash_set(*dirents, name, APR_HASH_KEY_STRING, dirent);
}
}
if (! (APR_STATUS_IS_ENOENT(status)))
return svn_error_wrap_apr(status, _("Can't read directory '%s'"),
- svn_dirent_local_style(path, pool));
+ svn_dirent_local_style(path, scratch_pool));
status = apr_dir_close(this_dir);
if (status)
return svn_error_wrap_apr(status, _("Error closing directory '%s'"),
- svn_dirent_local_style(path, pool));
+ svn_dirent_local_style(path, scratch_pool));
return SVN_NO_ERROR;
}
-svn_error_t *
-svn_io_get_dirents(apr_hash_t **dirents,
+static svn_error_t *
+svn_io_stat_dirent(const svn_io_dirent2_t **dirent_p,
const char *path,
- apr_pool_t *pool)
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
{
- /* Note that in C, padding is not allowed at the beginning of structs,
- so this is actually portable, since the kind field of svn_io_dirent_t
- is first in that struct. */
- return svn_io_get_dirents2(dirents, path, pool);
+ apr_finfo_t finfo;
+ svn_io_dirent2_t *dirent;
+
+ SVN_ERR(svn_io_stat(&finfo, path,
+ APR_FINFO_TYPE | APR_FINFO_NAME | APR_FINFO_LINK
+ | APR_FINFO_SIZE | APR_FINFO_MTIME,
+ scratch_pool));
+
+ dirent = svn_io_dirent2_create(result_pool);
+ map_apr_finfo_to_node_kind(&(dirent->kind), &(dirent->special), &finfo);
+
+ dirent->filesize = finfo.size;
+ dirent->mtime = finfo.mtime;
+
+ *dirent_p = dirent;
+
+ return SVN_NO_ERROR;
}
/* Pool userdata key for the error file passed to svn_io_start_cmd(). */