diff --git a/examples/gfind/CMakeLists.txt b/examples/gfind/CMakeLists.txt index ba05dac89d852bd0f146efae646f86180d3aaf58..cdb325c3127beef954cefb700c3a251a4cfff20f 100644 --- a/examples/gfind/CMakeLists.txt +++ b/examples/gfind/CMakeLists.txt @@ -2,7 +2,7 @@ set (CMAKE_CXX_STANDARD 14) add_executable(sfind sfind.cpp) if(GKFS_INSTALL_TESTS) - install(TARGETS sfind + install(TARGETS sfind DESTINATION ${CMAKE_INSTALL_BINDIR} ) endif() diff --git a/examples/gfind/gfind.cpp b/examples/gfind/gfind.cpp index 116b1344ca6bd9d78dc7de3430881b894cc2e637..80ac29579253b0fc68107073267c6b7f7bd5b1e9 100644 --- a/examples/gfind/gfind.cpp +++ b/examples/gfind/gfind.cpp @@ -33,263 +33,268 @@ using namespace std; /* Minimal struct needed for io500 find */ /* We could also do the filtering on the server */ struct dirent_extended { - size_t size; - time_t ctime; - unsigned short d_reclen; - unsigned char d_type; - char d_name[1]; + size_t size; + time_t ctime; + unsigned short d_reclen; + unsigned char d_type; + char d_name[1]; }; /* Function exported from GekkoFS LD_PRELOAD, code needs to be compiled with * -fPIC, if not will segfault */ -extern "C" int gkfs_getsingleserverdir(const char *path, - struct dirent_extended *dirp, - unsigned int count, int server) - __attribute__((weak)); +extern "C" int +gkfs_getsingleserverdir(const char* path, struct dirent_extended* dirp, + unsigned int count, int server) __attribute__((weak)); /* PFIND OPTIONS EXTENDED We need to add the GekkoFS mount dir and the number of * servers */ typedef struct { - std::string workdir{}; - int just_count; - int print_by_process; - char *results_dir; - int stonewall_timer; - int print_rates; - - char *timestamp_file; - char *name_pattern; - regex_t name_regex; - uint64_t size; - - int num_servers; - char *mountdir; - // optimizing parameters NOT USED - int queue_length; - int max_entries_per_iter; - int steal_from_next; // if true, then steal from the next process - int parallel_single_dir_access; // if 1, use hashing to parallelize single - // directory access, if 2 sequential increment - - int verbosity; + std::string workdir{}; + int just_count; + int print_by_process; + char* results_dir; + int stonewall_timer; + int print_rates; + + char* timestamp_file; + char* name_pattern; + regex_t name_regex; + uint64_t size; + + unsigned int num_servers; + char* mountdir; + // optimizing parameters NOT USED + int queue_length; + int max_entries_per_iter; + int steal_from_next; // if true, then steal from the next process + int parallel_single_dir_access; // if 1, use hashing to parallelize single + // directory access, if 2 sequential + // increment + + int verbosity; } pfind_options_t; typedef struct { - uint64_t ctime_min; - double stonewall_endtime; - FILE *logfile; - int needs_stat; + uint64_t ctime_min; + double stonewall_endtime; + FILE* logfile; + int needs_stat; } pfind_runtime_options_t; static pfind_runtime_options_t runtime; int pfind_rank; -static pfind_options_t *opt; +static pfind_options_t* opt; -void pfind_abort(const string str) { - printf("%s", str.c_str()); - exit(1); +void +pfind_abort(const string str) { + printf("%s", str.c_str()); + exit(1); } -static void pfind_print_help(pfind_options_t *res) { - printf("pfind \nSynopsis:\n" - "pfind [-newer ] [-size c] [-name " - "] [-regex ] [-S ] [-M ]\n" - "\tworkdir = \"%s\"\n" - "\t-newer = \"%s\"\n" - "\t-name|-regex = \"%s\"\n" - "\t-S: num servers = \"%s\"\n" - "\t-M: mountdir = \"%s\"\n" - "Optional flags\n" - "\t-h: prints the help\n" - "\t--help: prints the help without initializing MPI\n", - res->workdir, res->timestamp_file, res->name_pattern, res->num_servers, - res->mountdir); +static void +pfind_print_help(pfind_options_t* res) { + printf("pfind \nSynopsis:\n" + "pfind [-newer ] [-size c] [-name " + "] [-regex ] [-S ] [-M ]\n" + "\tworkdir = \"%s\"\n" + "\t-newer = \"%s\"\n" + "\t-name|-regex = \"%s\"\n" + "\t-S: num servers = \"%d\"\n" + "\t-M: mountdir = \"%s\"\n" + "Optional flags\n" + "\t-h: prints the help\n" + "\t--help: prints the help without initializing MPI\n", + res->workdir.c_str(), res->timestamp_file, res->name_pattern, + res->num_servers, res->mountdir); } MPI_Comm pfind_com; int pfind_size; -pfind_options_t *pfind_parse_args(int argc, char **argv, int force_print_help, - MPI_Comm com) { - MPI_Comm_rank(com, &pfind_rank); - MPI_Comm_size(com, &pfind_size); - pfind_com = com; - - pfind_options_t *res = (pfind_options_t *)malloc(sizeof(pfind_options_t)); - memset(res, 0, sizeof(pfind_options_t)); - int print_help = force_print_help; - - res->workdir = "./"; - res->results_dir = nullptr; - res->verbosity = 0; - res->timestamp_file = nullptr; - res->name_pattern = nullptr; - res->size = std::numeric_limits::max(); - res->queue_length = 100000; - res->max_entries_per_iter = 1000; - char *firstarg = nullptr; - - // when we find special args, we process them - // but we need to replace them with 0 so that getopt will ignore them - // and getopt will continue to process beyond them - for (auto i = 1; i < argc - 1; i++) { - if (strcmp(argv[i], "-newer") == 0) { - res->timestamp_file = strdup(argv[i + 1]); - argv[i][0] = 0; - argv[++i][0] = 0; - } else if (strcmp(argv[i], "-size") == 0) { - char *str = argv[i + 1]; - char extension = str[strlen(str) - 1]; - str[strlen(str) - 1] = 0; - res->size = atoll(str); - switch (extension) { - case 'c': - break; - default: - pfind_abort("Unsupported exension for -size\n"); - } - argv[i][0] = 0; - argv[++i][0] = 0; - } else if (strcmp(argv[i], "-name") == 0) { - res->name_pattern = (char *)malloc(strlen(argv[i + 1]) * 4 + 100); - // transform a traditional name pattern to a regex: - char *str = argv[i + 1]; - char *out = res->name_pattern; - int pos = 0; - for (unsigned i = 0; i < strlen(str); i++) { - if (str[i] == '*') { - pos += sprintf(out + pos, ".*"); - } else if (str[i] == '.') { - pos += sprintf(out + pos, "[.]"); - } else if (str[i] == '"' || str[i] == '\"') { - // erase the " - } else { - out[pos] = str[i]; - pos++; +pfind_options_t* +pfind_parse_args(int argc, char** argv, int force_print_help, MPI_Comm com) { + MPI_Comm_rank(com, &pfind_rank); + MPI_Comm_size(com, &pfind_size); + pfind_com = com; + + pfind_options_t* res = (pfind_options_t*) malloc(sizeof(pfind_options_t)); + memset(res, 0, sizeof(pfind_options_t)); + int print_help = force_print_help; + + res->workdir = "./"; + res->results_dir = nullptr; + res->verbosity = 0; + res->timestamp_file = nullptr; + res->name_pattern = nullptr; + res->size = std::numeric_limits::max(); + res->queue_length = 100000; + res->max_entries_per_iter = 1000; + char* firstarg = nullptr; + + // when we find special args, we process them + // but we need to replace them with 0 so that getopt will ignore them + // and getopt will continue to process beyond them + for(auto i = 1; i < argc - 1; i++) { + if(strcmp(argv[i], "-newer") == 0) { + res->timestamp_file = strdup(argv[i + 1]); + argv[i][0] = 0; + argv[++i][0] = 0; + } else if(strcmp(argv[i], "-size") == 0) { + char* str = argv[i + 1]; + char extension = str[strlen(str) - 1]; + str[strlen(str) - 1] = 0; + res->size = atoll(str); + switch(extension) { + case 'c': + break; + default: + pfind_abort("Unsupported exension for -size\n"); + } + argv[i][0] = 0; + argv[++i][0] = 0; + } else if(strcmp(argv[i], "-name") == 0) { + res->name_pattern = (char*) malloc(strlen(argv[i + 1]) * 4 + 100); + // transform a traditional name pattern to a regex: + char* str = argv[i + 1]; + char* out = res->name_pattern; + int pos = 0; + for(unsigned i = 0; i < strlen(str); i++) { + if(str[i] == '*') { + pos += sprintf(out + pos, ".*"); + } else if(str[i] == '.') { + pos += sprintf(out + pos, "[.]"); + } else if(str[i] == '"' || str[i] == '\"') { + // erase the " + } else { + out[pos] = str[i]; + pos++; + } + } + out[pos] = 0; + + auto ret = regcomp(&res->name_regex, res->name_pattern, 0); + if(ret) { + pfind_abort("Invalid regex for name given\n"); + } + argv[i][0] = 0; + argv[++i][0] = 0; + } else if(strcmp(argv[i], "-regex") == 0) { + res->name_pattern = strdup(argv[i + 1]); + auto ret = regcomp(&res->name_regex, res->name_pattern, 0); + if(ret) { + pfind_abort("Invalid regex for name given\n"); + } + argv[i][0] = 0; + argv[++i][0] = 0; + } else if(!firstarg) { + firstarg = strdup(argv[i]); + argv[i][0] = 0; } - } - out[pos] = 0; - - auto ret = regcomp(&res->name_regex, res->name_pattern, 0); - if (ret) { - pfind_abort("Invalid regex for name given\n"); - } - argv[i][0] = 0; - argv[++i][0] = 0; - } else if (strcmp(argv[i], "-regex") == 0) { - res->name_pattern = strdup(argv[i + 1]); - auto ret = regcomp(&res->name_regex, res->name_pattern, 0); - if (ret) { - pfind_abort("Invalid regex for name given\n"); - } - argv[i][0] = 0; - argv[++i][0] = 0; - } else if (!firstarg) { - firstarg = strdup(argv[i]); - argv[i][0] = 0; } - } - if (argc == 2) { - firstarg = strdup(argv[1]); - } - - int c; - while ((c = getopt(argc, argv, "CPs:r:vhD:xq:H:NM:S:")) != -1) { - if (c == -1) { - break; + if(argc == 2) { + firstarg = strdup(argv[1]); } - switch (c) { - case 'H': - res->parallel_single_dir_access = atoi(optarg); - break; - case 'N': - res->steal_from_next = 1; - break; - case 'x': - /* ignore fake arg that we added when we processed the extra args */ - break; - case 'P': - res->print_by_process = 1; - break; - case 'C': - res->just_count = 1; - break; - case 'D': - if (strcmp(optarg, "rates") == 0) { - res->print_rates = 1; - } else { - pfind_abort("Unsupported debug flag\n"); - } - break; - case 'h': - print_help = 1; - break; - case 'r': - res->results_dir = strdup(optarg); - break; - case 'q': - res->queue_length = atoi(optarg); - break; - if (res->queue_length < 10) { - pfind_abort("Queue must be at least 10 elements!\n"); - } - break; - case 's': - res->stonewall_timer = atol(optarg); - break; - case 'S': - res->num_servers = atoi(optarg); - break; - case 'M': - res->mountdir = strdup(optarg); - break; - case 'v': - res->verbosity++; - break; - case 0: - break; + int c; + while((c = getopt(argc, argv, "CPs:r:vhD:xq:H:NM:S:")) != -1) { + if(c == -1) { + break; + } + + switch(c) { + case 'H': + res->parallel_single_dir_access = atoi(optarg); + break; + case 'N': + res->steal_from_next = 1; + break; + case 'x': + /* ignore fake arg that we added when we processed the extra + * args */ + break; + case 'P': + res->print_by_process = 1; + break; + case 'C': + res->just_count = 1; + break; + case 'D': + if(strcmp(optarg, "rates") == 0) { + res->print_rates = 1; + } else { + pfind_abort("Unsupported debug flag\n"); + } + break; + case 'h': + print_help = 1; + break; + case 'r': + res->results_dir = strdup(optarg); + break; + case 'q': + res->queue_length = atoi(optarg); + break; + if(res->queue_length < 10) { + pfind_abort("Queue must be at least 10 elements!\n"); + } + break; + case 's': + res->stonewall_timer = atol(optarg); + break; + case 'S': + res->num_servers = atoi(optarg); + break; + case 'M': + res->mountdir = strdup(optarg); + break; + case 'v': + res->verbosity++; + break; + case 0: + break; + } } - } - if (res->verbosity > 2 && pfind_rank == 0) { - printf("Regex: %s\n", res->name_pattern); - } - - if (print_help) { - if (pfind_rank == 0) - pfind_print_help(res); - int init; - MPI_Initialized(&init); - if (init) { - MPI_Finalize(); + if(res->verbosity > 2 && pfind_rank == 0) { + printf("Regex: %s\n", res->name_pattern); } - exit(0); - } - if (!firstarg) { - pfind_abort("Error: pfind \n"); - } - res->workdir = firstarg; + if(print_help) { + if(pfind_rank == 0) + pfind_print_help(res); + int init; + MPI_Initialized(&init); + if(init) { + MPI_Finalize(); + } + exit(0); + } - return res; + if(!firstarg) { + pfind_abort("Error: pfind \n"); + } + res->workdir = firstarg; + + return res; } /* Master send a new path to the workers */ -void send_newPath(string path) { - auto count = path.size() + 1; - MPI_Bcast(&count, 1, MPI_INT, 0, MPI_COMM_WORLD); - MPI_Bcast((void *)path.c_str(), count, MPI_CHAR, 0, MPI_COMM_WORLD); +void +send_newPath(string path) { + auto count = path.size() + 1; + MPI_Bcast(&count, 1, MPI_INT, 0, MPI_COMM_WORLD); + MPI_Bcast((void*) path.c_str(), count, MPI_CHAR, 0, MPI_COMM_WORLD); } /* Clients get a new path, getting a "0" size char means there is no new path*/ -string recv_newPath() { - int count; - MPI_Bcast(&count, 1, MPI_INT, 0, MPI_COMM_WORLD); - if (count == 0) - return "Terminate"; - char buf[count]; - MPI_Bcast(buf, count, MPI_CHAR, 0, MPI_COMM_WORLD); - return buf; +string +recv_newPath() { + int count; + MPI_Bcast(&count, 1, MPI_INT, 0, MPI_COMM_WORLD); + if(count == 0) + return "Terminate"; + char buf[count]; + MPI_Bcast(buf, count, MPI_CHAR, 0, MPI_COMM_WORLD); + return buf; } /* Client Processing a path. @@ -299,215 +304,229 @@ string recv_newPath() { * server, which is enough for most cases * */ -void dirProcess(const string path, unsigned long long &checked, - unsigned long long &found, queue &dirs, - unsigned int world_rank, unsigned int world_size, - pfind_options_t *opt) { - struct dirent_extended *getdir = (struct dirent_extended *)malloc( - (sizeof(struct dirent_extended) + 255) * 1024 * 100); - memset(getdir, 0, (sizeof(struct dirent_extended) + 255) * 1024 * 100); - // cout << "PROCESSING " << world_rank << "/"<< world_size << " = " << path << - // endl; - - - int servers_per_node = ceil(opt->num_servers / (world_size - 1)); - if (servers_per_node == 0) - servers_per_node++; - for (int it = 0; it < servers_per_node; it++) { - auto server = (world_rank - 1) * servers_per_node + it; - if (server >= opt->num_servers) - break; - - unsigned long long total_size = 0; - auto n = gkfs_getsingleserverdir( - path.c_str(), getdir, - (sizeof(struct dirent_extended) + 255) * 1024 * 100, server); - struct dirent_extended *temp = getdir; - - while (total_size < n) { - if (strlen(temp->d_name) == 0) - break; - total_size += temp->d_reclen; - /* Queue directory to process */ - if (temp->d_type == 1) { - string slash; - if (path[path.size() - 1] != '/') - slash = "/"; - checked++; - dirs.push(path + slash + temp->d_name); - temp = reinterpret_cast(reinterpret_cast(temp) + - temp->d_reclen); - continue; +void +dirProcess(const string path, unsigned long long& checked, + unsigned long long& found, queue& dirs, + unsigned int world_rank, unsigned int world_size, + pfind_options_t* opt) { + struct dirent_extended* getdir = (struct dirent_extended*) malloc( + (sizeof(struct dirent_extended) + 255) * 1024 * 100); + memset(getdir, 0, (sizeof(struct dirent_extended) + 255) * 1024 * 100); + // cout << "PROCESSING " << world_rank << "/"<< world_size << " = " << path + // << endl; + + + int servers_per_node = ceil(opt->num_servers / (world_size - 1)); + if(servers_per_node == 0) + servers_per_node++; + for(int it = 0; it < servers_per_node; it++) { + unsigned int server = (world_rank - 1) * servers_per_node + it; + if(server >= opt->num_servers) + break; + + unsigned long long total_size = 0; + unsigned long long n = gkfs_getsingleserverdir( + path.c_str(), getdir, + (sizeof(struct dirent_extended) + 255) * 1024 * 100, server); + struct dirent_extended* temp = getdir; + + while(total_size < n) { + if(strlen(temp->d_name) == 0) + break; + total_size += temp->d_reclen; + /* Queue directory to process */ + if(temp->d_type == 1) { + string slash; + if(path[path.size() - 1] != '/') + slash = "/"; + checked++; + dirs.push(path + slash + temp->d_name); + temp = reinterpret_cast( + reinterpret_cast(temp) + temp->d_reclen); + continue; + } + + /* Find filtering */ + auto timeOK = true; + auto match = false; + if(opt->timestamp_file) { + if((uint64_t) temp->ctime < runtime.ctime_min) + timeOK = false; + } + + if(timeOK and (temp->size == opt->size or + opt->size == std::numeric_limits::max())) + if(!(opt->name_pattern && + regexec(&opt->name_regex, temp->d_name, 0, nullptr, 0))) { + found++; + match = true; + } + checked++; + if(opt->verbosity) + cout << temp->d_name << " -- " << opt->name_pattern + << " MATCH : " << match << endl; + temp = reinterpret_cast( + reinterpret_cast(temp) + temp->d_reclen); } - /* Find filtering */ - auto timeOK = true; - if (opt->timestamp_file) { - if ((uint64_t)temp->ctime < runtime.ctime_min) - timeOK = false; - } - if (timeOK and (temp->size == opt->size or opt->size == std::numeric_limits::max())) - if (!(opt->name_pattern && - regexec(&opt->name_regex, temp->d_name, 0, nullptr, 0))) - found++; - checked++; - temp = - reinterpret_cast(reinterpret_cast(temp) + temp->d_reclen); - } - } + } } -int process(char *processor_name, int world_rank, int world_size, - pfind_options_t *opt) { - // Print off a hello world message - - // INIT PFIND - memset(&runtime, 0, sizeof(pfind_runtime_options_t)); - int ret; - /* Get timestamp file */ - if (opt->timestamp_file) { - if (pfind_rank == 0) { - static struct stat timer_file{}; - if (lstat(opt->timestamp_file, &timer_file) != 0) { - printf("Could not open: \"%s\", error: %s", opt->timestamp_file, - strerror(errno)); - pfind_abort("\n"); - } - runtime.ctime_min = timer_file.st_ctime; - } - MPI_Bcast(&runtime.ctime_min, 1, MPI_INT, 0, pfind_com); - } - - auto iterations = 0; - if (world_rank == 0) { - queue dirs; - string workdir = opt->workdir; - workdir = workdir.substr(strlen(opt->mountdir), workdir.size()); - if (workdir.size() == 0) - workdir = "/"; - dirs.push(workdir); - - do { - - string processpath = dirs.front(); - dirs.pop(); - // DISTRIBUTE WORK - send_newPath(processpath); - auto received_strings = true; - // We need to gather new directories found (we use send-recv) - for (auto i = 1; i < world_size; i++) { - received_strings = true; - while (received_strings) { - received_strings = false; - // cout << " Checking from " << i << endl; - MPI_Status mpistatus; - MPI_Probe(i, 0, MPI_COMM_WORLD, &mpistatus); - int count; - MPI_Get_count(&mpistatus, MPI_CHAR, &count); - char buf[count]; - MPI_Recv(&buf, count, MPI_CHAR, i, 0, MPI_COMM_WORLD, &mpistatus); - if (count == 0) { - continue; - } - // cout << " Receiving from " << i << " ---- " << buf << endl; - string s = buf; - dirs.push(s); - received_strings = true; +int +process(char* processor_name, int world_rank, int world_size, + pfind_options_t* opt) { + // Print off a hello world message + + // INIT PFIND + memset(&runtime, 0, sizeof(pfind_runtime_options_t)); + /* Get timestamp file */ + if(opt->timestamp_file) { + if(pfind_rank == 0) { + static struct stat timer_file {}; + if(lstat(opt->timestamp_file, &timer_file) != 0) { + printf("Could not open: \"%s\", error: %s", opt->timestamp_file, + strerror(errno)); + pfind_abort("\n"); + } + runtime.ctime_min = timer_file.st_ctime; } - } - // cout << "NO more paths " << dirs.size() << endl; - } while (!dirs.empty()); - - auto count = 0; - MPI_Bcast(&count, 1, MPI_INT, 0, MPI_COMM_WORLD); - - MPI_Barrier(MPI_COMM_WORLD); - - unsigned long long *Array_checked = - (unsigned long long *)malloc(sizeof(unsigned long long) * world_size); - unsigned long long *Array_found = - (unsigned long long *)malloc(sizeof(unsigned long long) * world_size); - unsigned long long checked = 0; - unsigned long long found = 0; + MPI_Bcast(&runtime.ctime_min, 1, MPI_INT, 0, pfind_com); + } - MPI_Gather(&checked, 1, MPI_UNSIGNED_LONG_LONG, Array_checked, 1, - MPI_UNSIGNED_LONG_LONG, 0, MPI_COMM_WORLD); - MPI_Gather(&found, 1, MPI_UNSIGNED_LONG_LONG, Array_found, 1, - MPI_UNSIGNED_LONG_LONG, 0, MPI_COMM_WORLD); + if(world_rank == 0) { + queue dirs; + string workdir = opt->workdir; + workdir = workdir.substr(strlen(opt->mountdir), workdir.size()); + if(workdir.size() == 0) + workdir = "/"; + dirs.push(workdir); + + do { + + string processpath = dirs.front(); + dirs.pop(); + // DISTRIBUTE WORK + send_newPath(processpath); + auto received_strings = true; + // We need to gather new directories found (we use send-recv) + for(auto i = 1; i < world_size; i++) { + received_strings = true; + while(received_strings) { + received_strings = false; + // cout << " Checking from " << i << endl; + MPI_Status mpistatus; + MPI_Probe(i, 0, MPI_COMM_WORLD, &mpistatus); + int count; + MPI_Get_count(&mpistatus, MPI_CHAR, &count); + char buf[count]; + MPI_Recv(&buf, count, MPI_CHAR, i, 0, MPI_COMM_WORLD, + &mpistatus); + if(count == 0) { + continue; + } + // cout << " Receiving from " << i << " ---- " << buf << + // endl; + string s = buf; + dirs.push(s); + received_strings = true; + } + } + // cout << "NO more paths " << dirs.size() << endl; + } while(!dirs.empty()); + + auto count = 0; + MPI_Bcast(&count, 1, MPI_INT, 0, MPI_COMM_WORLD); + + MPI_Barrier(MPI_COMM_WORLD); + + unsigned long long* Array_checked = (unsigned long long*) malloc( + sizeof(unsigned long long) * world_size); + unsigned long long* Array_found = (unsigned long long*) malloc( + sizeof(unsigned long long) * world_size); + unsigned long long checked = 0; + unsigned long long found = 0; + + MPI_Gather(&checked, 1, MPI_UNSIGNED_LONG_LONG, Array_checked, 1, + MPI_UNSIGNED_LONG_LONG, 0, MPI_COMM_WORLD); + MPI_Gather(&found, 1, MPI_UNSIGNED_LONG_LONG, Array_found, 1, + MPI_UNSIGNED_LONG_LONG, 0, MPI_COMM_WORLD); + + for(int i = 0; i < world_size; i++) { + checked += Array_checked[i]; + found += Array_found[i]; + } - for (int i = 0; i < world_size; i++) { - checked += Array_checked[i]; - found += Array_found[i]; + cout << "MATCHED " << found << "/" << checked << endl; } - cout << "MATCHED " << found << "/" << checked << endl; - } - - else { - unsigned long long checked = 0; - unsigned long long found = 0; - while (1) { - - string toProcess = recv_newPath(); - if (toProcess == "Terminate") { - break; - } - // cout << "REceived " << toProcess << " --- " << world_rank << endl; - queue dirs; - - dirProcess(toProcess, checked, found, dirs, world_rank, world_size, opt); - // Send NEW DIRS to master - while (!dirs.empty()) { - string s = dirs.front(); - dirs.pop(); - // cout << world_rank << " --> Sending " << s << endl; - MPI_Send((void *)s.c_str(), (s.size() + 1), MPI_CHAR, 0, 0, - MPI_COMM_WORLD); - } - // cout << world_rank << " --> Sending 0 " << endl; - MPI_Send((void *)0, 0, MPI_CHAR, 0, 0, MPI_COMM_WORLD); - } + else { + unsigned long long checked = 0; + unsigned long long found = 0; + while(1) { + + string toProcess = recv_newPath(); + if(toProcess == "Terminate") { + break; + } + // cout << "REceived " << toProcess << " --- " << world_rank << + // endl; + queue dirs; + + dirProcess(toProcess, checked, found, dirs, world_rank, world_size, + opt); + // Send NEW DIRS to master + while(!dirs.empty()) { + string s = dirs.front(); + dirs.pop(); + // cout << world_rank << " --> Sending " << s << endl; + MPI_Send((void*) s.c_str(), (s.size() + 1), MPI_CHAR, 0, 0, + MPI_COMM_WORLD); + } + // cout << world_rank << " --> Sending 0 " << endl; + MPI_Send((void*) 0, 0, MPI_CHAR, 0, 0, MPI_COMM_WORLD); + } - MPI_Barrier(MPI_COMM_WORLD); - MPI_Gather(&checked, 1, MPI_UNSIGNED_LONG_LONG, nullptr, 1, - MPI_UNSIGNED_LONG_LONG, 0, MPI_COMM_WORLD); - MPI_Gather(&found, 1, MPI_UNSIGNED_LONG_LONG, nullptr, 1, - MPI_UNSIGNED_LONG_LONG, 0, MPI_COMM_WORLD); - } + MPI_Barrier(MPI_COMM_WORLD); + MPI_Gather(&checked, 1, MPI_UNSIGNED_LONG_LONG, nullptr, 1, + MPI_UNSIGNED_LONG_LONG, 0, MPI_COMM_WORLD); + MPI_Gather(&found, 1, MPI_UNSIGNED_LONG_LONG, nullptr, 1, + MPI_UNSIGNED_LONG_LONG, 0, MPI_COMM_WORLD); + } - return 0; + return 0; } -int main(int argc, char **argv) { +int +main(int argc, char** argv) { - for (int i = 0; i < argc; i++) { - if (strcmp(argv[i], "--help") == 0) { - argv[i][0] = 0; - pfind_rank = 0; - pfind_parse_args(argc, argv, 1, MPI_COMM_SELF); - exit(0); + for(int i = 0; i < argc; i++) { + if(strcmp(argv[i], "--help") == 0) { + argv[i][0] = 0; + pfind_rank = 0; + pfind_parse_args(argc, argv, 1, MPI_COMM_SELF); + exit(0); + } } - } - // Initialize the MPI environment - MPI_Init(&argc, &argv); + // Initialize the MPI environment + MPI_Init(&argc, &argv); - // Get the number of processes - int world_size; - MPI_Comm_size(MPI_COMM_WORLD, &world_size); + // Get the number of processes + int world_size; + MPI_Comm_size(MPI_COMM_WORLD, &world_size); - // Get the rank of the process - int world_rank; - MPI_Comm_rank(MPI_COMM_WORLD, &world_rank); + // Get the rank of the process + int world_rank; + MPI_Comm_rank(MPI_COMM_WORLD, &world_rank); - opt = pfind_parse_args(argc, argv, 0, MPI_COMM_WORLD); - // cout << opt->num_servers << " -- " << opt->mountdir << endl; - // Get the name of the processor - char processor_name[MPI_MAX_PROCESSOR_NAME]; - int name_len; - MPI_Get_processor_name(processor_name, &name_len); + opt = pfind_parse_args(argc, argv, 0, MPI_COMM_WORLD); + // cout << opt->num_servers << " -- " << opt->mountdir << endl; + // Get the name of the processor + char processor_name[MPI_MAX_PROCESSOR_NAME]; + int name_len; + MPI_Get_processor_name(processor_name, &name_len); - process(processor_name, world_rank, world_size, opt); + process(processor_name, world_rank, world_size, opt); - // Finalize the MPI environment. - MPI_Finalize(); + // Finalize the MPI environment. + MPI_Finalize(); } diff --git a/examples/gfind/sfind.cpp b/examples/gfind/sfind.cpp index 9702638853aa9a888013d6750cdb133154a7485a..a0c2aa53e89e8ee5f544980554909ea71beb8d1f 100644 --- a/examples/gfind/sfind.cpp +++ b/examples/gfind/sfind.cpp @@ -20,11 +20,9 @@ #include #include #include -#include +#include #include #include -#include -#include #include using namespace std; @@ -32,238 +30,214 @@ using namespace std; /* Minimal struct needed for io500 find */ /* We could also do the filtering on the server */ struct dirent_extended { - size_t size; - time_t ctime; - unsigned short d_reclen; - unsigned char d_type; - char d_name[1]; + size_t size; + time_t ctime; + unsigned short d_reclen; + unsigned char d_type; + char d_name[1]; }; /* Function exported from GekkoFS LD_PRELOAD, code needs to be compiled with * -fPIC */ -extern "C" int gkfs_getsingleserverdir(const char *path, - struct dirent_extended *dirp, - unsigned int count, int server) - __attribute__((weak)); +extern "C" int +gkfs_getsingleserverdir(const char* path, struct dirent_extended* dirp, + unsigned int count, int server) __attribute__((weak)); /* PFIND OPTIONS EXTENDED We need to add the GekkoFS mount dir and the number of * servers */ -typedef struct { - std::string workdir{}; - int just_count; - int print_by_process; - char *results_dir; - int stonewall_timer; - int print_rates; - - char *timestamp_file; - char *name_pattern; - regex_t name_regex; - uint64_t size; - - int num_servers; - char *mountdir; - // optimizing parameters NOT USED - int queue_length; - int max_entries_per_iter; - int steal_from_next; // if true, then steal from the next process - int parallel_single_dir_access; // if 1, use hashing to parallelize single - // directory access, if 2 sequential increment - - int verbosity; -} pfind_options_t; +class pfind_options_t { +public: + std::string workdir{}; + int stonewall_timer; + + char* timestamp_file; + char* name_pattern; + regex_t name_regex; + uint64_t size; + + int num_servers; + char* mountdir; + // optimizing parameters NOT USED + + + int verbosity; + + pfind_options_t() { + workdir = ""; + stonewall_timer = 0; + timestamp_file = nullptr; + name_pattern = nullptr; + size = 0; + num_servers = 0; + mountdir = nullptr; + verbosity = 0; + }; +}; + typedef struct { - uint64_t ctime_min; - double stonewall_endtime; - FILE *logfile; - int needs_stat; + uint64_t ctime_min; + double stonewall_endtime; + FILE* logfile; + int needs_stat; } pfind_runtime_options_t; static pfind_runtime_options_t runtime; int pfind_rank; -static pfind_options_t *opt; -void pfind_abort(const std::string str) { - printf("%s", str.c_str()); - exit(1); +void +pfind_abort(const std::string& str) { + printf("%s", str.c_str()); + exit(1); } -static void pfind_print_help(pfind_options_t *res) { - printf("pfind \nSynopsis:\n" - "pfind [-newer ] [-size c] [-name " - "] [-regex ] [-S ] [-M ]\n" - "\tworkdir = \"%s\"\n" - "\t-newer = \"%s\"\n" - "\t-name|-regex = \"%s\"\n" - "\t-S: num servers = \"%s\"\n" - "\t-M: mountdir = \"%s\"\n" - "Optional flags\n" - "\t-h: prints the help\n" - "\t--help: prints the help without initializing MPI\n",res->workdir, - res->timestamp_file, res->name_pattern, res->num_servers, - res->mountdir ); +static void +pfind_print_help(pfind_options_t& res) { + printf("pfind \nSynopsis:\n" + "pfind [-newer ] [-size c] [-name " + "] [-regex ] [-S ] [-M ]\n" + "\tworkdir = \"%s\"\n" + "\t-newer = \"%s\"\n" + "\t-name|-regex = \"%s\"\n" + "\t-S: num servers = \"%d\"\n" + "\t-M: mountdir = \"%s\"\n" + "Optional flags\n" + "\t-h: prints the help\n" + "\t--help: prints the help without initializing MPI\n", + res.workdir.c_str(), res.timestamp_file, res.name_pattern, + res.num_servers, res.mountdir); } -int pfind_size; -pfind_options_t *pfind_parse_args(int argc, char **argv, int force_print_help){ - - pfind_rank = 0; - pfind_size = 1; - - pfind_options_t *res = (pfind_options_t *)malloc(sizeof(pfind_options_t)); - memset(res, 0, sizeof(pfind_options_t)); - auto print_help = force_print_help; - - res->workdir = "./"; - res->results_dir = nullptr; - res->verbosity = 0; - res->timestamp_file = nullptr; - res->name_pattern = nullptr; - res->size = std::numeric_limits::max(); - res->queue_length = 100000; - res->max_entries_per_iter = 1000; - char *firstarg = nullptr; - - // when we find special args, we process them - // but we need to replace them with 0 so that getopt will ignore them - // and getopt will continue to process beyond them - for (auto i = 1; i < argc - 1; i++) { - if (strcmp(argv[i], "-newer") == 0) { - res->timestamp_file = strdup(argv[i + 1]); - argv[i][0] = 0; - argv[++i][0] = 0; - } else if (strcmp(argv[i], "-size") == 0) { - char *str = argv[i + 1]; - char extension = str[strlen(str) - 1]; - str[strlen(str) - 1] = 0; - res->size = atoll(str); - switch (extension) { - case 'c': - break; - default: - pfind_abort("Unsupported exension for -size\n"); - } - argv[i][0] = 0; - argv[++i][0] = 0; - } else if (strcmp(argv[i], "-name") == 0) { - res->name_pattern = (char *)malloc(strlen(argv[i + 1]) * 4 + 100); - // transform a traditional name pattern to a regex: - char *str = argv[i + 1]; - char *out = res->name_pattern; - auto pos = 0; - for (auto i = 0; i < strlen(str); i++) { - if (str[i] == '*') { - pos += sprintf(out + pos, ".*"); - } else if (str[i] == '.') { - pos += sprintf(out + pos, "[.]"); - } else if (str[i] == '"' || str[i] == '\"') { - // erase the " - } else { - out[pos] = str[i]; - pos++; + +pfind_options_t +pfind_parse_args(int argc, char** argv, int force_print_help) { + + pfind_rank = 0; + + auto print_help = force_print_help; + + pfind_options_t res; + res.workdir = "./"; + res.verbosity = 0; + res.timestamp_file = nullptr; + res.name_pattern = nullptr; + res.size = std::numeric_limits::max(); + + char* firstarg = nullptr; + + // when we find special args, we process them + // but we need to replace them with 0 so that getopt will ignore them + // and getopt will continue to process beyond them + for(auto i = 1; i < argc - 1; i++) { + if(strcmp(argv[i], "-newer") == 0) { + res.timestamp_file = strdup(argv[i + 1]); + argv[i][0] = 0; + argv[++i][0] = 0; + } else if(strcmp(argv[i], "-size") == 0) { + char* str = argv[i + 1]; + char extension = str[strlen(str) - 1]; + str[strlen(str) - 1] = 0; + res.size = atoll(str); + if(extension != 'c') { + pfind_abort("Unsupported extension for -size\n"); + } + argv[i][0] = 0; + argv[++i][0] = 0; + } else if(strcmp(argv[i], "-name") == 0) { + res.name_pattern = (char*) malloc(strlen(argv[i + 1]) * 4 + 100); + // transform a traditional name pattern to a regex: + char* str = argv[i + 1]; + char* out = res.name_pattern; + + + auto pos = 0; + for(size_t k = 0; k < strlen(str); k++) { + if(str[k] == '*') { + pos += sprintf(out + pos, ".*"); + } else if(str[k] == '.') { + pos += sprintf(out + pos, "[.]"); + } else if(str[k] == '"' || str[k] == '\"') { + // erase the " + } else { + out[pos] = str[k]; + pos++; + } + } + out[pos] = 0; + + int ret = regcomp(&res.name_regex, res.name_pattern, 0); + if(ret) { + pfind_abort("Invalid regex for name given\n"); + } + argv[i][0] = 0; + argv[++i][0] = 0; + } else if(strcmp(argv[i], "-regex") == 0) { + res.name_pattern = strdup(argv[i + 1]); + int ret = regcomp(&res.name_regex, res.name_pattern, 0); + if(ret) { + pfind_abort("Invalid regex for name given\n"); + } + argv[i][0] = 0; + argv[++i][0] = 0; + } else if(!firstarg) { + firstarg = strdup(argv[i]); + argv[i][0] = 0; } - } - out[pos] = 0; - - int ret = regcomp(&res->name_regex, res->name_pattern, 0); - if (ret) { - pfind_abort("Invalid regex for name given\n"); - } - argv[i][0] = 0; - argv[++i][0] = 0; - } else if (strcmp(argv[i], "-regex") == 0) { - res->name_pattern = strdup(argv[i + 1]); - int ret = regcomp(&res->name_regex, res->name_pattern, 0); - if (ret) { - pfind_abort("Invalid regex for name given\n"); - } - argv[i][0] = 0; - argv[++i][0] = 0; - } else if (!firstarg) { - firstarg = strdup(argv[i]); - argv[i][0] = 0; } - } - if (argc == 2) { - firstarg = strdup(argv[1]); - } - - int c; - while ((c = getopt(argc, argv, "CPs:r:vhD:xq:H:NM:S:")) != -1) { - if (c == -1) { - break; + if(argc == 2) { + firstarg = strdup(argv[1]); } - switch (c) { - case 'H': - res->parallel_single_dir_access = atoi(optarg); - break; - case 'N': - res->steal_from_next = 1; - break; - case 'x': - /* ignore fake arg that we added when we processed the extra args */ - break; - case 'P': - res->print_by_process = 1; - break; - case 'C': - res->just_count = 1; - break; - case 'D': - if (strcmp(optarg, "rates") == 0) { - res->print_rates = 1; - } else { - pfind_abort("Unsupported debug flag\n"); - } - break; - case 'h': - print_help = 1; - break; - case 'r': - res->results_dir = strdup(optarg); - break; - case 'q': - res->queue_length = atoi(optarg); - break; - if (res->queue_length < 10) { - pfind_abort("Queue must be at least 10 elements!\n"); - } - break; - case 's': - res->stonewall_timer = atol(optarg); - break; - case 'S': - res->num_servers = atoi(optarg); - break; - case 'M': - res->mountdir = strdup(optarg); - break; - case 'v': - res->verbosity++; - break; - case 0: - break; + int c; + while((c = getopt(argc, argv, "CPs:r:vhD:xq:H:NM:S:")) != -1) { + if(c == -1) { + break; + } + + switch(c) { + case 'x': + /* ignore fake arg that we added when we processed the extra + * args */ + break; + case 'h': + print_help = 1; + break; + case 's': + res.stonewall_timer = atoi(optarg); + break; + case 'S': + res.num_servers = atoi(optarg); + break; + case 'M': + res.mountdir = strdup(optarg); + break; + case 'v': + res.verbosity++; + break; + case 0: + break; + default: + cerr << "Unknown parameter" << endl; + break; + } + } + if(res.verbosity > 2 && pfind_rank == 0) { + printf("Regex: %s\n", res.name_pattern); } - } - if (res->verbosity > 2 && pfind_rank == 0) { - printf("Regex: %s\n", res->name_pattern); - } - - if (print_help) { - if (pfind_rank == 0) - pfind_print_help(res); - exit(0); - } - - if (!firstarg) { - pfind_abort("Error: pfind \n"); - } - res->workdir = firstarg; - - return res; + + if(print_help) { + if(pfind_rank == 0) + pfind_print_help(res); + exit(0); + } + + if(!firstarg) { + pfind_abort("Error: pfind \n"); + } + res.workdir = firstarg; + + return res; } /* Client Processing a path. @@ -273,109 +247,122 @@ pfind_options_t *pfind_parse_args(int argc, char **argv, int force_print_help){ * server, which is enough for most cases * */ -void dirProcess(const string path, unsigned long long &checked, - unsigned long long &found, queue &dirs, - unsigned int world_rank, unsigned int world_size, - pfind_options_t *opt) { - struct dirent_extended *getdir = (struct dirent_extended *)malloc( - (sizeof(struct dirent_extended) + 255) * 1024 * 100); - memset(getdir, 0, (sizeof(struct dirent_extended) + 255) * 1024 * 100); - // cout << "PROCESSING " << world_rank << "/"<< world_size << " = " << path << - // endl; - - for (auto server = 0; server < opt->num_servers; server++) { - unsigned long long total_size = 0; - auto n = gkfs_getsingleserverdir( - path.c_str(), getdir, - (sizeof(struct dirent_extended) + 255) * 1024 * 100, server); - struct dirent_extended *temp = getdir; - - while (total_size < n) { - if (strlen(temp->d_name) == 0) - break; - total_size += temp->d_reclen; - /* Queue directory to process */ - if (temp->d_type == 1) { - string slash; - if (path[path.size() - 1] != '/') - slash = "/"; - checked++; - dirs.push(path + slash + temp->d_name); - temp = - reinterpret_cast(reinterpret_cast(temp) + temp->d_reclen); - continue; - } - /* Find filtering */ - auto timeOK = true; - if (opt->timestamp_file) { - if ((uint64_t)temp->ctime < runtime.ctime_min) - timeOK = false; - } - if (timeOK and (temp->size == opt->size or opt->size == std::numeric_limits::max())) - if (!(opt->name_pattern && - regexec(&opt->name_regex, temp->d_name, 0, nullptr, 0))) - found++; - checked++; - temp = reinterpret_cast(reinterpret_cast(temp) + temp->d_reclen); +void +dirProcess(const string& path, unsigned long long& checked, + unsigned long long& found, queue& dirs, + pfind_options_t& opt) { + auto* getdir = (struct dirent_extended*) malloc( + (sizeof(struct dirent_extended) + 255) * 1024 * 100); + memset(getdir, 0, (sizeof(struct dirent_extended) + 255) * 1024 * 100); + + + for(auto server = 0; server < opt.num_servers; server++) { + unsigned long long total_size = 0; + unsigned long long n = gkfs_getsingleserverdir( + path.c_str(), getdir, + (sizeof(struct dirent_extended) + 255) * 1024 * 100, server); + struct dirent_extended* temp = getdir; + if(opt.verbosity) + cerr << "[" << n << "] " << path.c_str() << endl; + while(total_size < n) { + if(strlen(temp->d_name) == 0) + break; + total_size += temp->d_reclen; + /* Queue directory to process */ + if(temp->d_type == 1) { + string slash; + if(path[path.size() - 1] != '/') + slash = "/"; + checked++; + dirs.push(path + slash + temp->d_name); + temp = reinterpret_cast( + reinterpret_cast(temp) + temp->d_reclen); + continue; + } + /* Find filtering */ + auto timeOK = true; + if(opt.timestamp_file) { + if((uint64_t) temp->ctime < runtime.ctime_min) + timeOK = false; + } + + if(timeOK and (temp->size == opt.size or + opt.size == std::numeric_limits::max())) + if(!(opt.name_pattern && + regexec(&opt.name_regex, temp->d_name, 0, nullptr, 0))) + found++; + checked++; + + if(opt.verbosity) + cerr << temp->d_name << endl; + temp = reinterpret_cast( + reinterpret_cast(temp) + temp->d_reclen); + } } - } } -int process(pfind_options_t *opt) { - // Print off a hello world message - unsigned long long found,checked; - // INIT PFIND - found = 0; - checked = 0; - memset(&runtime, 0, sizeof(pfind_runtime_options_t)); - auto ret = 0; - /* Get timestamp file */ - if (opt->timestamp_file) { - if (pfind_rank == 0) { - static struct stat timer_file{}; - if (lstat(opt->timestamp_file, &timer_file) != 0) { - printf("Could not open: \"%s\", error: %s", opt->timestamp_file, - strerror(errno)); - pfind_abort("\n"); - } - runtime.ctime_min = timer_file.st_ctime; +int +process(pfind_options_t& opt) { + // Print off a hello world message + unsigned long long found, checked; + // INIT PFIND + found = 0; + checked = 0; + memset(&runtime, 0, sizeof(pfind_runtime_options_t)); + /* Get timestamp file */ + if(opt.timestamp_file) { + if(pfind_rank == 0) { + static struct stat timer_file {}; + if(lstat(opt.timestamp_file, &timer_file) != 0) { + printf("Could not open: \"%s\", error: %s", opt.timestamp_file, + strerror(errno)); + pfind_abort("\n"); + } + runtime.ctime_min = timer_file.st_ctime; + } } - } - - auto iterations = 0; - queue dirs; - string workdir = opt->workdir; - workdir = workdir.substr(strlen(opt->mountdir), workdir.size()); - if (workdir.size() == 0) - workdir = "/"; - dirs.push(workdir); - do { - string processpath = dirs.front(); - dirs.pop(); - - dirProcess(processpath, checked, found, dirs, 0, 1, opt); - // cout << "NO more paths " << dirs.size() << endl; - } while (!dirs.empty()); + queue dirs; + string workdir = opt.workdir; + workdir = workdir.substr(strlen(opt.mountdir), workdir.size()); + if(workdir.empty()) + workdir = "/"; + if(opt.verbosity) + cerr << "STARTING PATH " << workdir << endl; + dirs.push(workdir); + + do { + string processpath = dirs.front(); + dirs.pop(); + if(opt.verbosity) + cerr << "PROCESSING " << processpath << endl; + dirProcess(processpath, checked, found, dirs, opt); + // cout << "NO more paths " << dirs.size() << endl; + } while(!dirs.empty()); cout << "MATCHED " << found << "/" << checked << endl; - return 0; + return 0; } -int main(int argc, char **argv) { - - for (auto i = 0; i < argc; i++) { - if (strcmp(argv[i], "--help") == 0) { - argv[i][0] = 0; - pfind_rank = 0; - pfind_parse_args(argc, argv, 1); - exit(0); +int +main(int argc, char** argv) { + if(gkfs_getsingleserverdir == nullptr) { + cerr << "LD_PRELOAD not correctly defined or incorrect gekkofs version." + << endl; + exit(1); } - } - - opt = pfind_parse_args(argc, argv, 0); - process(opt); + for(auto i = 0; i < argc; i++) { + if(strcmp(argv[i], "--help") == 0) { + argv[i][0] = 0; + pfind_rank = 0; + pfind_parse_args(argc, argv, 1); + exit(0); + } + } + pfind_options_t opt; + opt = pfind_parse_args(argc, argv, 0); + process(opt); } diff --git a/tests/integration/directories/test_directories.py b/tests/integration/directories/test_directories.py index 4a60617dd890943aff8bef053b06e96c6217741a..5b7b26f8d9f21b660b0c6d2b2e8b0d9d0458b733 100644 --- a/tests/integration/directories/test_directories.py +++ b/tests/integration/directories/test_directories.py @@ -178,6 +178,7 @@ def test_mkdir(gkfs_daemon, gkfs_client): return +# Test dirents_singleserver using an external application calling a gekkofs function. def test_extended(gkfs_daemon, gkfs_shell, gkfs_client): topdir = gkfs_daemon.mountdir / "test_extended" longer = Path(topdir.parent, topdir.name + "_plus") @@ -193,24 +194,30 @@ def test_extended(gkfs_daemon, gkfs_shell, gkfs_client): assert ret.retval == 0 + logger.info ("Creating 3 directories (2xlevel 1, 1xlevel 2)") + # create topdir/dir_a ret = gkfs_client.mkdir( dir_a, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO) assert ret.retval == 0 + # create topdir/dir_b ret = gkfs_client.mkdir( dir_b, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO) assert ret.retval == 0 + # create topdir/dir_a/subdir_a ret = gkfs_client.mkdir( subdir_a, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO) assert ret.retval == 0 + logger.info ("Creating a file at level 1"); + # create a topdir/file_a with 1 byte ret = gkfs_client.open(file_a, os.O_CREAT, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO) @@ -221,6 +228,7 @@ def test_extended(gkfs_daemon, gkfs_shell, gkfs_client): assert ret.retval == 1 + logger.info ("Search contents with size 1 and a name matching *f*_a*, we should get 1 hit, from 4 checked entries") cmd = gkfs_shell.sfind( topdir, '-M', @@ -228,11 +236,11 @@ def test_extended(gkfs_daemon, gkfs_shell, gkfs_client): '-S', 1, '-name', - '*_k*' + '*f*_a*' ) assert cmd.exit_code == 0 - assert cmd.stdout.decode() == "MATCHED 0/4\n" + assert cmd.stdout.decode() == "MATCHED 1/4\n" @pytest.mark.skip(reason="invalid errno returned on success") @pytest.mark.parametrize("directory_path",