Skip to content

Commit 2dc19b0

Browse files
committed
BottomUp min/max level and start at subdirectories
added -y, -z, and -D for gufi_rollup and gufi_treesummary_all be careful when using -z - need to have completed -y; otherwise might error or return bad results
1 parent 2b07fff commit 2dc19b0

File tree

11 files changed

+376
-48
lines changed

11 files changed

+376
-48
lines changed

include/BottomUp.h

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,8 @@ struct BottomUp {
114114

115115
/* Signature of function for processing */
116116
/* directories while traversing a tree */
117-
typedef int (*BU_f)(void *user_struct);
117+
typedef int (*BU_descend_f)(void *user_struct, int *keep_going);
118+
typedef int (*BU_ascend_f) (void *user_struct);
118119

119120
/* ****************************************************************** */
120121
/*
@@ -130,7 +131,8 @@ typedef int (*BU_f)(void *user_struct);
130131
*/
131132
QPTPool_t *parallel_bottomup_init(const size_t thread_count,
132133
const size_t user_struct_size,
133-
BU_f descend, BU_f ascend,
134+
const size_t min_level, const size_t max_level,
135+
BU_descend_f descend, BU_ascend_f ascend,
134136
const int track_non_dirs,
135137
const int generate_alt_name);
136138

@@ -150,9 +152,11 @@ int parallel_bottomup_fini(QPTPool_t *pool);
150152
* This function wraps parallel_bottomup_{init,enqueue,fini}.
151153
*/
152154
int parallel_bottomup(char **root_names, const size_t root_count,
155+
const size_t min_level, const size_t max_level,
156+
const refstr_t *subtree_list,
153157
const size_t thread_count,
154158
const size_t user_struct_size,
155-
BU_f descend, BU_f ascend,
159+
BU_descend_f descend, BU_ascend_f ascend,
156160
const int track_non_dirs,
157161
const int generate_alt_name,
158162
void *extra_args);

src/BottomUp.c

Lines changed: 102 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,13 @@ processed before processing the current one
8383
#include "utils.h"
8484

8585
/* define so that descend and ascend always have valid functions to call */
86-
static int noop(void *user_struct) {
86+
static int noop_descend(void *user_struct, int *keep_going) {
87+
(void) user_struct;
88+
(void) keep_going;
89+
return 0;
90+
}
91+
92+
static int noop_ascend(void *user_struct) {
8793
(void) user_struct;
8894
return 0;
8995
}
@@ -99,8 +105,10 @@ void bottomup_destroy(void *p) {
99105

100106
struct UserArgs {
101107
size_t user_struct_size;
102-
BU_f descend;
103-
BU_f ascend;
108+
size_t min_level;
109+
size_t max_level;
110+
BU_descend_f descend;
111+
BU_ascend_f ascend;
104112
int track_non_dirs;
105113
int generate_alt_name;
106114
trie_t *skip;
@@ -210,7 +218,10 @@ static int ascend_to_top(QPTPool_t *ctx, const size_t id, void *data, void *args
210218
bu->tid.up = id;
211219

212220
/* call user ascend function */
213-
const int asc_rc = ua->ascend(bu);
221+
int asc_rc = 0;
222+
if ((ua->min_level <= bu->level) && (bu->level <= ua->max_level)) {
223+
asc_rc = ua->ascend(bu);
224+
}
214225

215226
/* clean up 'struct BottomUp's here, when they are */
216227
/* children instead of when they are the parent */
@@ -348,12 +359,19 @@ static int descend_to_bottom(QPTPool_t *ctx, const size_t id, void *data, void *
348359

349360
/* this will probably be a bottleneck since subdirectories won't */
350361
/* be queued/processed while the descend function runs */
351-
const int desc_rc = ua->descend(bu);
362+
int desc_rc = 0;
363+
int keep_descending = 1;
364+
if ((ua->min_level <= bu->level) && (bu->level <= ua->max_level)) {
365+
desc_rc = ua->descend(bu, &keep_descending);
366+
}
352367

353-
bu->refs.remaining = bu->subdir_count;
368+
/* if the descent function succeeded */
354369
if (desc_rc == 0) {
355370
/* if there are subdirectories, this directory cannot go back up just yet */
356-
if (bu->subdir_count) {
371+
if (keep_descending && (next_level <= ua->max_level) && bu->subdir_count) {
372+
/* decrement each time child triggers parent for processing */
373+
bu->refs.remaining = bu->subdir_count;
374+
357375
/* have to lock to prevent subdirs from getting popped */
358376
/* off before all of them have been enqueued */
359377
pthread_mutex_lock(&bu->refs.mutex);
@@ -367,8 +385,10 @@ static int descend_to_bottom(QPTPool_t *ctx, const size_t id, void *data, void *
367385
}
368386
pthread_mutex_unlock(&bu->refs.mutex);
369387
}
370-
/* start working upwards */
371388
else {
389+
bu->refs.remaining = 0;
390+
391+
/* start working upwards */
372392
QPTPool_enqueue(ctx, id, ascend_to_top, bu);
373393
}
374394
}
@@ -385,7 +405,8 @@ static int descend_to_bottom(QPTPool_t *ctx, const size_t id, void *data, void *
385405

386406
QPTPool_t *parallel_bottomup_init(const size_t thread_count,
387407
const size_t user_struct_size,
388-
BU_f descend, BU_f ascend,
408+
const size_t min_level, const size_t max_level,
409+
BU_descend_f descend, BU_ascend_f ascend,
389410
const int track_non_dirs,
390411
const int generate_alt_name) {
391412
if (user_struct_size < sizeof(struct BottomUp)) {
@@ -395,8 +416,10 @@ QPTPool_t *parallel_bottomup_init(const size_t thread_count,
395416

396417
struct UserArgs *ua = calloc(1, sizeof(*ua));
397418
ua->user_struct_size = user_struct_size;
398-
ua->descend = descend?descend:noop;
399-
ua->ascend = ascend?ascend:noop;
419+
ua->min_level = min_level;
420+
ua->max_level = max_level;
421+
ua->descend = descend?descend:noop_descend;
422+
ua->ascend = ascend?ascend:noop_ascend;
400423
ua->track_non_dirs = track_non_dirs;
401424
ua->generate_alt_name = generate_alt_name;
402425

@@ -434,9 +457,7 @@ int parallel_bottomup_enqueue(QPTPool_t *pool,
434457
new_pathname(root, path, len, NULL, 0);
435458

436459
if (ua->generate_alt_name) {
437-
int ret = new_alt_pathname(root, root->name, root->name_len, NULL, 0);
438-
439-
if (ret) {
460+
if (new_alt_pathname(root, root->name, root->name_len, NULL, 0)) {
440461
fprintf(stderr, "%s could not fit into ALT_NAME buffer\n", root->name);
441462
bottomup_destroy(root);
442463
return -1;
@@ -451,6 +472,52 @@ int parallel_bottomup_enqueue(QPTPool_t *pool,
451472
return 0;
452473
}
453474

475+
static int parallel_bottomup_enqueue_subdirs(QPTPool_t *pool,
476+
const char *path, const size_t len,
477+
const size_t min_level, const refstr_t *subtree_list,
478+
void *extra_args) {
479+
struct UserArgs *ua = NULL;
480+
QPTPool_get_args(pool, (void **) &ua);
481+
482+
FILE *file = fopen(subtree_list->data, "r");
483+
if (!file) {
484+
const int err = errno;
485+
fprintf(stderr, "could not open directory list file \"%s\": %s (%d)\n",
486+
subtree_list->data, strerror(err), err);
487+
return -1;
488+
}
489+
490+
char *line = NULL;
491+
size_t n = 0;
492+
ssize_t got = 0;
493+
while ((got = getline(&line, &n, file)) != -1) {
494+
/* remove trailing CRLF */
495+
const size_t line_len = trailing_non_match_index(line, got, "\r\n", 2);
496+
497+
struct BottomUp *root = (struct BottomUp *) calloc(ua->user_struct_size, 1);
498+
new_pathname(root, path, len, line, line_len);
499+
500+
if (ua->generate_alt_name) {
501+
if (new_alt_pathname(root, root->name, root->name_len, NULL, 0)) {
502+
fprintf(stderr, "%s could not fit into ALT_NAME buffer\n", root->name);
503+
bottomup_destroy(root);
504+
return -1;
505+
}
506+
}
507+
508+
root->parent = NULL;
509+
root->extra_args = extra_args;
510+
root->level = min_level;
511+
512+
QPTPool_enqueue(pool, 0, descend_to_bottom, root);
513+
}
514+
515+
free(line);
516+
fclose(file);
517+
518+
return 0;
519+
}
520+
454521
int parallel_bottomup_fini(QPTPool_t *pool) {
455522
if (!pool) {
456523
return -1;
@@ -481,13 +548,24 @@ int parallel_bottomup_fini(QPTPool_t *pool) {
481548
}
482549

483550
int parallel_bottomup(char **root_names, const size_t root_count,
551+
const size_t min_level, const size_t max_level,
552+
const refstr_t *subtree_list,
484553
const size_t thread_count,
485554
const size_t user_struct_size,
486-
BU_f descend, BU_f ascend,
555+
BU_descend_f descend, BU_ascend_f ascend,
487556
const int track_non_dirs,
488557
const int generate_alt_name,
489558
void *extra_args) {
490-
QPTPool_t *pool = parallel_bottomup_init(thread_count, user_struct_size, descend, ascend,
559+
if (min_level && subtree_list->data && subtree_list->len) {
560+
if (root_count > 1) {
561+
fprintf(stderr, "Error: Only one root may be provided when a -y and -D are both provided\n");
562+
return -1;
563+
}
564+
}
565+
566+
QPTPool_t *pool = parallel_bottomup_init(thread_count, user_struct_size,
567+
min_level, max_level,
568+
descend, ascend,
491569
track_non_dirs, generate_alt_name);
492570
if (!pool) {
493571
return -1;
@@ -498,8 +576,14 @@ int parallel_bottomup(char **root_names, const size_t root_count,
498576

499577
/* enqueue all root directories */
500578
size_t good_roots = 0;
501-
for(size_t i = 0; i < root_count; i++) {
502-
good_roots += !parallel_bottomup_enqueue(pool, root_names[i], strlen(root_names[i]), extra_args);
579+
if (min_level && subtree_list->data && subtree_list->len) {
580+
good_roots += !parallel_bottomup_enqueue_subdirs(pool, root_names[0], strlen(root_names[0]),
581+
min_level, subtree_list, extra_args);
582+
}
583+
else {
584+
for(size_t i = 0; i < root_count; i++) {
585+
good_roots += !parallel_bottomup_enqueue(pool, root_names[i], strlen(root_names[i]), extra_args);
586+
}
503587
}
504588

505589
return -(parallel_bottomup_fini(pool) || (root_count != good_roots));

src/gufi_rollup.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -485,6 +485,11 @@ static int can_rollup(struct input *in,
485485
sqlite3 *dst) {
486486
/* Not checking arguments */
487487

488+
/* not deep enough */
489+
if (rollup->data.level < in->min_level) {
490+
return 0;
491+
}
492+
488493
char *err = NULL;
489494

490495
/* default to cannot roll up */
@@ -860,7 +865,7 @@ int main(int argc, char *argv[]) {
860865
clock_gettime(CLOCK_MONOTONIC, &runtime.start);
861866

862867
struct PoolArgs pa;
863-
process_args_and_maybe_exit("hHvn:L:X", 1, "GUFI_index ...", &pa.in);
868+
process_args_and_maybe_exit("hHvn:L:Xy:z:D:", 1, "GUFI_index ...", &pa.in);
864869

865870
init_template_db(&pa.xattr_template);
866871
if (create_xattrs_template(&pa.xattr_template) != 0) {
@@ -887,6 +892,8 @@ int main(int argc, char *argv[]) {
887892
argc -= idx;
888893

889894
const int rc = parallel_bottomup(argv, argc,
895+
pa.in.min_level, pa.in.max_level,
896+
&pa.in.subtree_list,
890897
pa.in.maxthreads,
891898
sizeof(struct RollUp),
892899
NULL, rollup,

src/gufi_treesummary_all.c

Lines changed: 48 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,39 @@ OF SUCH DAMAGE.
7070
#include "dbutils.h"
7171
#include "utils.h"
7272

73-
static int treesummary(void *args) {
73+
static int treesummary_found(void *args, int count, char **data, char **columns) {
74+
int *keep_going = (int *) args;
75+
*keep_going = 0;
76+
return 0;
77+
}
78+
79+
static int treesummary_descend(void *args, int *keep_going) {
80+
struct BottomUp *dir = (struct BottomUp *) args;
81+
82+
char dbname[MAXPATH];
83+
SNFORMAT_S(dbname, sizeof(dbname), 2,
84+
dir->name, dir->name_len,
85+
"/" DBNAME, DBNAME_LEN + 1);
86+
87+
sqlite3 *db = opendb(dbname, SQLITE_OPEN_READONLY, 1, 0, NULL, NULL);
88+
89+
int rc = !db;
90+
if (db) {
91+
char *err = NULL;
92+
/* check if treesummary table exists - if it does, don't descend */
93+
if (sqlite3_exec(db, TREESUMMARY_EXISTS, treesummary_found, &keep_going, &err) != SQLITE_OK) {
94+
fprintf(stderr, "Error: Could not check for existence of treesummary table: %s\n", err);
95+
sqlite3_free(err);
96+
rc = 1;
97+
}
98+
}
99+
100+
closedb(db);
101+
102+
return rc;
103+
}
104+
105+
static int treesummary_ascend(void *args) {
74106
struct BottomUp *dir = (struct BottomUp *) args;
75107

76108
char dbname[MAXPATH];
@@ -80,8 +112,9 @@ static int treesummary(void *args) {
80112

81113
sqlite3 *db = opendb(dbname, SQLITE_OPEN_READWRITE, 1, 0, create_treesummary_tables, NULL);
82114

83-
int rc = !!db;
115+
int rc = !db;
84116
if (db) {
117+
/* the treesummary table was not found, so create it */
85118
rc = bottomup_collect_treesummary(db, dir->name, &dir->subdirs, ROLLUPSCORE_CHECK);
86119
}
87120

@@ -91,7 +124,7 @@ static int treesummary(void *args) {
91124
}
92125

93126
static void sub_help(void) {
94-
printf("GUFI_index path to GUFI index\n");
127+
printf("GUFI_tree path to GUFI tree\n");
95128
printf("\n");
96129
}
97130

@@ -103,15 +136,20 @@ int main(int argc, char *argv[]) {
103136
* control which options are parsed for each program.
104137
*/
105138
struct input in;
106-
process_args_and_maybe_exit("hHvn:", 1, "GUFI_index", &in);
139+
process_args_and_maybe_exit("hHvn:y:z:D:", 1, "GUFI_index", &in);
140+
141+
/* if -z was provided, assume that all directories under the level have treesummary tables */
142+
BU_descend_f desc = (in.max_level == (size_t) -1)?treesummary_descend:NULL;
107143

108144
const int rc = parallel_bottomup(argv + idx, argc - idx,
109-
in.maxthreads,
110-
sizeof(struct BottomUp),
111-
NULL, treesummary,
112-
0,
113-
0,
114-
NULL);
145+
in.min_level, in.max_level,
146+
&in.subtree_list,
147+
in.maxthreads,
148+
sizeof(struct BottomUp),
149+
desc, treesummary_ascend,
150+
0,
151+
0,
152+
&in);
115153

116154
input_fini(&in);
117155

src/parallel_rmr.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,8 @@ int main(int argc, char * argv[]) {
110110
process_args_and_maybe_exit("hHvn:", 1, "directory ...", &in);
111111

112112
const int rc = parallel_bottomup(argv + idx, argc - idx,
113+
0, (size_t) -1,
114+
NULL,
113115
in.maxthreads,
114116
sizeof(struct BottomUp),
115117
NULL, rm_dir,

0 commit comments

Comments
 (0)