From 07ca0be3c58d4e8ed8137d9ab11fbddc82607cf8 Mon Sep 17 00:00:00 2001 From: Christian Kamm Date: Mon, 24 Aug 2015 11:09:34 +0200 Subject: [PATCH] csync_excluded: Another speedup #3638 Build a list of path components outside of the exclude pattern loop. --- csync/src/csync_exclude.c | 78 ++++++++----------- csync/src/std/c_string.c | 19 +++++ csync/src/std/c_string.h | 13 ++++ csync/tests/csync_tests/check_csync_exclude.c | 5 ++ 4 files changed, 70 insertions(+), 45 deletions(-) diff --git a/csync/src/csync_exclude.c b/csync/src/csync_exclude.c index baf14b70e..d5cee4368 100644 --- a/csync/src/csync_exclude.c +++ b/csync/src/csync_exclude.c @@ -44,24 +44,7 @@ static #endif int _csync_exclude_add(c_strlist_t **inList, const char *string) { - c_strlist_t *list; - - if (*inList == NULL) { - *inList = c_strlist_new(32); - if (*inList == NULL) { - return -1; - } - } - - if ((*inList)->count == (*inList)->size) { - list = c_strlist_expand(*inList, 2 * (*inList)->size); - if (list == NULL) { - return -1; - } - *inList = list; - } - - return c_strlist_add(*inList, string); + return c_strlist_add_grow(inList, string); } int csync_exclude_load(const char *fname, c_strlist_t **list) { @@ -281,6 +264,31 @@ static CSYNC_EXCLUDE_TYPE _csync_excluded_common(c_strlist_t *excludes, const ch goto out; } + /* Build a list of path components to check. */ + c_strlist_t *path_components = c_strlist_new(32); + char *path_split = strdup(path); + size_t len = strlen(path_split); + for (int j = len; ; --j) { + // read backwards until a path separator is found + if (j != 0 && path_split[j-1] != '/') { + continue; + } + + // check 'basename', i.e. for "/foo/bar/fi" we'd check 'fi', 'bar', 'foo' + if (path_split[j] != 0) { + c_strlist_add_grow(&path_components, path_split + j); + } + + if (j == 0 || !check_leading_dirs) { + break; + } + + // check 'dirname', i.e. for "/foo/bar/fi" we'd check '/foo/bar', '/foo' + path_split[j-1] = '\0'; + c_strlist_add_grow(&path_components, path_split); + } + SAFE_FREE(path_split); + /* Loop over all exclude patterns and evaluate the given path */ for (i = 0; match == CSYNC_NOT_EXCLUDED && i < excludes->count; i++) { bool match_dirs_only = false; @@ -319,41 +327,21 @@ static CSYNC_EXCLUDE_TYPE _csync_excluded_common(c_strlist_t *excludes, const ch /* if still not excluded, check each component and leading directory of the path */ if (match == CSYNC_NOT_EXCLUDED) { - 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 '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; - } - } - check_segname = true; - - if (j == 0 || !check_leading_dirs) { - 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); + size_t j = 0; + if (match_dirs_only && filetype == CSYNC_FTW_TYPE_FILE) { + j = 1; // skip the first entry, which is bname + } + for (; j < path_components->count; ++j) { + rc = csync_fnmatch(pattern, path_components->vector[j], 0); if (rc == 0) { match = type; break; } } - SAFE_FREE(segmented_path); } SAFE_FREE(pattern_stored); } + c_strlist_destroy(path_components); out: diff --git a/csync/src/std/c_string.c b/csync/src/std/c_string.c index e248f6c7c..e21d4374e 100644 --- a/csync/src/std/c_string.c +++ b/csync/src/std/c_string.c @@ -215,6 +215,25 @@ int c_strlist_add(c_strlist_t *strlist, const char *string) { return 0; } +int c_strlist_add_grow(c_strlist_t **strlist, const char *string) { + if (*strlist == NULL) { + *strlist = c_strlist_new(32); + if (*strlist == NULL) { + return -1; + } + } + + if ((*strlist)->count == (*strlist)->size) { + c_strlist_t *list = c_strlist_expand(*strlist, 2 * (*strlist)->size); + if (list == NULL) { + return -1; + } + *strlist = list; + } + + return c_strlist_add(*strlist, string); +} + void c_strlist_clear(c_strlist_t *strlist) { size_t i = 0; diff --git a/csync/src/std/c_string.h b/csync/src/std/c_string.h index 640cb500e..60bc010da 100644 --- a/csync/src/std/c_string.h +++ b/csync/src/std/c_string.h @@ -112,6 +112,19 @@ c_strlist_t *c_strlist_expand(c_strlist_t *strlist, size_t size); */ int c_strlist_add(c_strlist_t *strlist, const char *string); +/** + * @brief Add a string to the stringlist, growing it if necessary + * + * Duplicates the string and stores it in the stringlist. + * It also initializes the stringlist if it starts out as null. + * + * @param strlist Stringlist to add the string. + * @param string String to add. + * + * @return 0 on success, less than 0 and errno set if an error occured. + */ +int c_strlist_add_grow(c_strlist_t **strlist, const char *string); + /** * @brief Removes all strings from the list. * diff --git a/csync/tests/csync_tests/check_csync_exclude.c b/csync/tests/csync_tests/check_csync_exclude.c index 0bcbda94f..c73fe5f5c 100644 --- a/csync/tests/csync_tests/check_csync_exclude.c +++ b/csync/tests/csync_tests/check_csync_exclude.c @@ -90,6 +90,11 @@ static void check_csync_excluded(void **state) CSYNC *csync = *state; int rc; + rc = csync_excluded(csync, "", CSYNC_FTW_TYPE_FILE); + assert_int_equal(rc, CSYNC_NOT_EXCLUDED); + rc = csync_excluded(csync, "/", CSYNC_FTW_TYPE_FILE); + assert_int_equal(rc, CSYNC_NOT_EXCLUDED); + rc = csync_excluded(csync, "krawel_krawel", CSYNC_FTW_TYPE_FILE); assert_int_equal(rc, CSYNC_NOT_EXCLUDED); rc = csync_excluded(csync, ".kde/share/config/kwin.eventsrc", CSYNC_FTW_TYPE_FILE); -- 2.30.2