int path_disk_size_info_get_r(const char *path, int64_t max_secs, struct path_disk_size_info **state) { int64_t start_time = time(0); int result = 0; if(!*state) { /* if state is null, there is no state, and path is the root of the measurement. */ *state = calloc(1, sizeof(struct path_disk_size_info)); } struct path_disk_size_info *s = *state; /* shortcut for *state, so we do not need to type (*state)->... */ /* if no current_dirs, we begin a new measurement. */ if(!s->current_dirs) { s->complete_measurement = 0; struct DIR_with_name *here = malloc(sizeof(struct DIR_with_name)); if((here->dir = opendir(path))) { here->name = xxstrdup(path); s->current_dirs = list_create(0); s->size_so_far = 0; s->count_so_far = 1; /* count the root directory */ list_push_tail(s->current_dirs, here); } else { debug(D_DEBUG, "error reading disk usage on directory: %s.\n", path); s->size_so_far = -1; s->count_so_far = -1; s->complete_measurement = 1; result = -1; goto timeout; } } struct DIR_with_name *tail; while((tail = list_peek_tail(s->current_dirs))) { struct dirent *entry; struct stat file_info; while((entry = readdir(tail->dir))) { if( strcmp(".", entry->d_name) == 0 || strcmp("..", entry->d_name) == 0) continue; char composed_path[PATH_MAX]; if(entry->d_name[0] == '/') { strncpy(composed_path, entry->d_name, PATH_MAX); } else { snprintf(composed_path, PATH_MAX, "%s/%s", tail->name, entry->d_name); } if(lstat(composed_path, &file_info) < 0) { if(errno == ENOENT) { /* our DIR structure is stale, and a file went away. We simply do nothing. */ } else { debug(D_DEBUG, "error reading disk usage on '%s'.\n", path); result = -1; } continue; } s->count_so_far++; if(S_ISREG(file_info.st_mode)) { s->size_so_far += file_info.st_size; } else if(S_ISDIR(file_info.st_mode)) { struct DIR_with_name *branch = malloc(sizeof(struct DIR_with_name)); if((branch->dir = opendir(composed_path))) { /* future while we'll read from the branch */ branch->name = xxstrdup(composed_path); list_push_head(s->current_dirs, branch); } else { free(branch); result = -1; continue; } } else if(S_ISLNK(file_info.st_mode)) { /* do nothing, avoiding infinite loops. */ } if(max_secs > -1) { if( time(0) - start_time >= max_secs ) { goto timeout; } } } /* we are done reading a complete directory, and we go to the next in the queue */ tail = list_pop_tail(s->current_dirs); closedir(tail->dir); free(tail->name); free(tail); } list_delete(s->current_dirs); s->current_dirs = NULL; /* signal that a new measurement is needed, if state structure is reused. */ s->complete_measurement = 1; timeout: if(s->complete_measurement) { /* if a complete measurement has been done, then update * for the found value */ s->last_byte_size_complete = s->size_so_far; s->last_file_count_complete = s->count_so_far; } else { /* else, we hit a timeout. measurement reported is conservative, from * what we knew, and know so far. */ s->last_byte_size_complete = MAX(s->last_byte_size_complete, s->size_so_far); s->last_file_count_complete = MAX(s->last_file_count_complete, s->count_so_far); } return result; }
int main(int argc, char *argv[]) { struct work_queue *q; int port = WORK_QUEUE_DEFAULT_PORT; if(argc != 4) { printf("Usage: work_queue_workload_simulator <workload_spec> <logfile> <proj_name> \n"); exit(1); } struct list *specs = get_workload_specs(argv[1]); if(!specs) { printf("Failed to load a non-empty workload specification.\n"); exit(1); } created_files = list_create(); if(!created_files) { printf("Failed to allocate memory for a list to store created files.\n"); exit(1); } // open log file logfile = fopen(argv[2], "a"); if(!logfile) { printf("Couldn't open logfile %s: %s\n", argv[2], strerror(errno)); exit(1); } q = work_queue_create(port); if(!q) { printf("couldn't listen on port %d: %s\n", port, strerror(errno)); goto fail; exit(1); } printf("listening on port %d...\n", work_queue_port(q)); // specifying the right modes work_queue_specify_master_mode(q, WORK_QUEUE_MASTER_MODE_CATALOG); work_queue_specify_name(q, argv[3]); work_queue_specify_estimate_capacity_on(q, 1); // report capacity on int time_elapsed = 0; // in seconds int series_id = 0; time_t start_time = time(0); log_work_queue_status(q); while(1) { struct task_series *ts = (struct task_series *)list_peek_tail(specs); if(!ts) { while(!work_queue_empty(q)) { // wait until all tasks to finish wait_for_task(q, 5); } break; } else { time_elapsed = time(0) - start_time; int time_until_next_submit = ts->submit_time - time_elapsed; if(time_until_next_submit <=0) { list_pop_tail(specs); printf("time elapsed: %d seconds\n", time_elapsed); if(!submit_task_series(q, ts, series_id)) { // failed to submit tasks fprintf(stderr, "Failed to submit tasks.\n"); goto fail; } free(ts); series_id++; } else { time_t stoptime = start_time + ts->submit_time; while(!work_queue_empty(q)) { int timeout = stoptime - time(0); if(timeout > 0) { wait_for_task(q, timeout); } else { break; } } time_t current_time = time(0); if(current_time < stoptime) { sleep(stoptime - current_time); } } } } printf("all tasks complete!\n"); work_queue_delete(q); remove_created_files(); fclose(logfile); return 0; fail: remove_created_files(); fclose(logfile); exit(1); }