[Pkg-owncloud-commits] [owncloud-client] 03/218: csync_exclude: Speed up siginificantly #3638

Sandro Knauß hefee-guest at moszumanska.debian.org
Sat Oct 17 14:30:30 UTC 2015


This is an automated email from the git hooks/post-receive script.

hefee-guest pushed a commit to branch master
in repository owncloud-client.

commit 20f4ec6b6756ced80cfc92a5a891ec353b25055d
Author: Christian Kamm <mail at ckamm.de>
Date:   Fri Aug 21 14:20:27 2015 +0200

    csync_exclude: Speed up siginificantly #3638
    
    The performance test indicates a speedup of around 3x for paths
    with around 12 components.
---
 csync/src/csync_exclude.c                     | 65 +++++++++++----------------
 csync/tests/csync_tests/check_csync_exclude.c | 43 ++++++++++++++++++
 2 files changed, 70 insertions(+), 38 deletions(-)

diff --git a/csync/src/csync_exclude.c b/csync/src/csync_exclude.c
index 7a29e37..42adfe8 100644
--- a/csync/src/csync_exclude.c
+++ b/csync/src/csync_exclude.c
@@ -191,7 +191,6 @@ CSYNC_EXCLUDE_TYPE csync_excluded_no_ctx(c_strlist_t *excludes, const char *path
   const char *p = NULL;
   char *bname = NULL;
   char *dname = NULL;
-  char *prev_dname = NULL;
   char *conflict = NULL;
   int rc = -1;
   CSYNC_EXCLUDE_TYPE match = CSYNC_NOT_EXCLUDED;
@@ -340,54 +339,44 @@ CSYNC_EXCLUDE_TYPE csync_excluded_no_ctx(c_strlist_t *excludes, const char *path
           }
       }
 
-      /* if still not excluded, check each component of the path */
+      /* if still not excluded, check each component and leading directory of the path */
       if (match == CSYNC_NOT_EXCLUDED) {
-          int trailing_component = 1;
-          dname = c_dirname(path);
-          bname = c_basename(path);
-
-          if (bname == NULL || dname == NULL) {
-              match = CSYNC_NOT_EXCLUDED;
-	      SAFE_FREE(bname);
-	      SAFE_FREE(dname);
-              SAFE_FREE(pattern_stored);
-              goto out;
-          }
+          char *segmented_path = strdup(path);
+          size_t len = strlen(segmented_path);
+          bool check_segname = !match_dirs_only || filetype != CSYNC_FTW_TYPE_FILE;
+          for (int j = len; ; --j) {
+              // read backwards until a path separator
+              if (j != 0 && segmented_path[j-1] != '/') {
+                  continue;
+              }
 
-          /* Check each component of the path */
-          do {
-              /* Do not check the bname if its a file and the pattern matches dirs only. */
-              if ( !(trailing_component == 1 /* it is the trailing component */
-                     && match_dirs_only      /* but only directories are matched by the pattern */
-                     && filetype == CSYNC_FTW_TYPE_FILE) ) {
-                  /* Check the name component against the pattern */
-                  rc = csync_fnmatch(pattern, bname, 0);
+              // check 'basename', i.e. for "/foo/bar/fi" we'd check 'fi', 'bar', 'foo'
+              if (check_segname && segmented_path[j] != 0) {
+                  rc = csync_fnmatch(pattern, segmented_path + j, 0);
                   if (rc == 0) {
                       match = type;
+                      break;
                   }
               }
-              if (!(c_streq(dname, ".") || c_streq(dname, "/"))) {
-                  rc = csync_fnmatch(pattern, dname, 0);
-                  if (rc == 0) {
-                      match = type;
-                  }
+              check_segname = true;
+
+              if (j == 0) {
+                  break;
+              }
+
+              // check 'dirname', i.e. for "/foo/bar/fi" we'd check '/foo/bar', '/foo'
+              segmented_path[j-1] = '\0';
+              rc = csync_fnmatch(pattern, segmented_path, 0);
+              if (rc == 0) {
+                  match = type;
+                  break;
               }
-              trailing_component = 0;
-              prev_dname = dname;
-              SAFE_FREE(bname);
-              bname = c_basename(prev_dname);
-              dname = c_dirname(prev_dname);
-              SAFE_FREE(prev_dname);
-
-          } while( match == CSYNC_NOT_EXCLUDED && !c_streq(dname, ".")
-                     && !c_streq(dname, "/") );
+          }
+          SAFE_FREE(segmented_path);
       }
       SAFE_FREE(pattern_stored);
-      SAFE_FREE(bname);
-      SAFE_FREE(dname);
   }
 
-
 out:
 
   return match;
diff --git a/csync/tests/csync_tests/check_csync_exclude.c b/csync/tests/csync_tests/check_csync_exclude.c
index 94430ea..b0b57ff 100644
--- a/csync/tests/csync_tests/check_csync_exclude.c
+++ b/csync/tests/csync_tests/check_csync_exclude.c
@@ -19,6 +19,7 @@
  */
 #include "config_csync.h"
 #include <string.h>
+#include <time.h>
 
 #include "torture.h"
 
@@ -170,8 +171,25 @@ static void check_csync_pathes(void **state)
     rc = csync_excluded(csync, "meep/excl", CSYNC_FTW_TYPE_DIR);
     assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
 
+    rc = csync_excluded(csync, "meep/excl/file", CSYNC_FTW_TYPE_FILE);
+    assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
+
     rc = csync_excluded(csync, "/excl", CSYNC_FTW_TYPE_FILE);
     assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
+
+    _csync_exclude_add(&csync->excludes, "/excludepath/withsubdir");
+
+    rc = csync_excluded(csync, "/excludepath/withsubdir", CSYNC_FTW_TYPE_DIR);
+    assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
+
+    rc = csync_excluded(csync, "/excludepath/withsubdir", CSYNC_FTW_TYPE_FILE);
+    assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
+
+    rc = csync_excluded(csync, "/excludepath/withsubdir2", CSYNC_FTW_TYPE_DIR);
+    assert_int_equal(rc, CSYNC_NOT_EXCLUDED);
+
+    rc = csync_excluded(csync, "/excludepath/withsubdir/foo", CSYNC_FTW_TYPE_DIR);
+    assert_int_equal(rc, CSYNC_FILE_EXCLUDE_LIST);
 }
 
 static void check_csync_is_windows_reserved_word() {
@@ -190,7 +208,31 @@ static void check_csync_is_windows_reserved_word() {
     assert_true(csync_is_windows_reserved_word("Z:"));
     assert_true(csync_is_windows_reserved_word("M:"));
     assert_true(csync_is_windows_reserved_word("m:"));
+}
+
+static void check_csync_excluded_performance(void **state)
+{
+    CSYNC *csync = *state;
+
+    const int N = 10000;
+    int totalRc = 0;
+
+    // Being able to use QElapsedTimer for measurement would be nice...
+    struct timeval before, after;
+    gettimeofday(&before, 0);
+
+    for (int i = 0; i < N; ++i) {
+        totalRc += csync_excluded(csync, "/this/is/quite/a/long/path/with/many/components", CSYNC_FTW_TYPE_DIR);
+        totalRc += csync_excluded(csync, "/1/2/3/4/5/6/7/8/9/10/11/12/13/14/15/16/17/18/19/20/21/22/23/24/25/26/27/29", CSYNC_FTW_TYPE_FILE);
+    }
+    assert_int_equal(totalRc, CSYNC_NOT_EXCLUDED); // mainly to avoid optimization
+
+    gettimeofday(&after, 0);
 
+    const double total = (after.tv_sec - before.tv_sec)
+            + (after.tv_usec - before.tv_usec) / 1.0e6;
+    const double perCallMs = total / 2 / N * 1000;
+    printf("csync_excluded: %f ms per call\n", perCallMs);
 }
 
 int torture_run_tests(void)
@@ -201,6 +243,7 @@ int torture_run_tests(void)
         unit_test_setup_teardown(check_csync_excluded, setup_init, teardown),
         unit_test_setup_teardown(check_csync_pathes, setup_init, teardown),
         unit_test_setup_teardown(check_csync_is_windows_reserved_word, setup_init, teardown),
+        unit_test_setup_teardown(check_csync_excluded_performance, setup_init, teardown),
     };
 
     return run_tests(tests);

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-owncloud/owncloud-client.git



More information about the Pkg-owncloud-commits mailing list