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(). */


Reply via email to