/* this returns cached result */ gfarm_error_t gfs_stat_cached_internal(const char *path, struct gfs_stat *st) { struct gfarm_hash_entry *entry; struct stat_cache_data *data; struct timeval now; if (stat_cache == NULL) { gfarm_error_t e = gfs_stat_cache_init(); if (e != GFARM_ERR_NO_ERROR) return (e); } gettimeofday(&now, NULL); gfs_stat_cache_expire_internal(&now); entry = gfarm_hash_lookup(stat_cache, path, strlen(path) + 1); if (entry != NULL) { #ifdef DIRCACHE_DEBUG gflog_debug(GFARM_MSG_1000092, "%ld.%06ld: gfs_stat_cached(%s): hit (%d)", (long)now.tv_sec,(long)now.tv_usec, path,stat_cache_count); #endif data = gfarm_hash_entry_data(entry); return (gfs_stat_copy(st, &data->st)); } #ifdef DIRCACHE_DEBUG gflog_debug(GFARM_MSG_1000093, "%ld.%06ld: gfs_stat_cached(%s): miss (%d)", (long)now.tv_sec, (long)now.tv_usec, path, stat_cache_count); #endif return (gfs_stat_caching(path, st)); }
int gfarm_error_to_errno(const char *error) { struct gfarm_hash_entry *p; int i; if (gfarm_errlist_hashtab == NULL) gfarm_errlist_hashtab_initialize(); for (i = 0; i < GFARM_ARRAY_LENGTH(gfarm_errno_error_map); i++) { if (error == gfarm_errno_error_map[i].gfarm_error) return (gfarm_errno_error_map[i].unix_errno); } /* * The reason why we compare string content rather than string * address here is that strerror(3) may always copy error string * to its internal buffer. * * XXX - If we always use sys_errlist[] rather than strerror(3), * is it ok to just compare string address? */ /* XXX - if locale LC_MESSAGES is changed, this may not work. */ p = gfarm_hash_lookup(gfarm_errlist_hashtab, error, strlen(error) + 1); if (p != NULL) return (*(int *)gfarm_hash_entry_data(p)); return (EINVAL); /* last resort, cannot mapped into errno */ }
static char * cache_path_info_remove(const char *pathname) { struct gfarm_hash_entry *he; int pathlen; struct path_info_cache *pic; if (!cache_path_info_init()) return (GFARM_PATH_INFO_CACHE_CANCEL); pathlen = strlen(pathname); he = gfarm_hash_lookup(cache_table, pathname, pathlen); if (he != NULL) { pic = gfarm_hash_entry_data(he); if (pic != NULL) { if (pic->noent == CACHE_SET) gfarm_path_info_free(&pic->info); if (gfarm_hash_purge(cache_table, pathname, pathlen)) { _debug("! remove path_info cache: %s\n", pathname); current_cache_num--; return (NULL); } } } return "cache_path_info_remove: no path_info cache"; }
static gfarm_error_t create_hostlist_by_domain_and_hash(struct file_info *finfo, char *domain, struct gfarm_hash_table *hosthash, int *nhostsp, char ***hostsp, int **portsp) { int ninfo, i, j, *ports, nhosts; struct gfarm_host_sched_info *infos; char **hosts; gfarm_error_t e; e = schedule_host_domain(finfo->pathname, domain, &ninfo, &infos); if (e != GFARM_ERR_NO_ERROR) return (e); /* sort 'infos' in descending order wrt available capacity */ qsort(infos, ninfo, sizeof(*infos), compare_available_capacity_r); /* eliminate file system nodes that do not have enough space */ for (i = 0; i < ninfo; ++i) /* note that disk_avail is the number of 1K blocks */ if (infos[i].disk_avail * 1024 < gfarm_get_minimum_free_disk_space()) break; nhosts = i; /* XXX - abandon CPU load and available capacity */ GFARM_MALLOC_ARRAY(hosts, nhosts); if (hosts == NULL) { gfarm_host_sched_info_free(ninfo, infos); return (GFARM_ERR_NO_MEMORY); } GFARM_MALLOC_ARRAY(ports, nhosts); if (ports == NULL) { free(hosts); gfarm_host_sched_info_free(ninfo, infos); return (GFARM_ERR_NO_MEMORY); } for (i = 0, j = 0; i < nhosts; ++i) { char *host = infos[i].host; if (hosthash == NULL || gfarm_hash_lookup(hosthash, host, strlen(host) + 1)) { hosts[j] = strdup(host); ports[j] = infos[i].port; if (hosts[j] == NULL) { gfarm_strings_free_deeply(j, hosts); return (GFARM_ERR_NO_MEMORY); } ++j; } } gfarm_host_sched_info_free(ninfo, infos); *hostsp = hosts; *portsp = ports; *nhostsp = j; return (e); }
static int is_host_runnable(struct string_filter *self, const char *host) { struct host_runnable_filter *filter = (struct host_runnable_filter *)self; struct gfarm_hash_entry *entry = gfarm_hash_lookup(filter->hosts_state, host, strlen(host) + 1); struct search_idle_host_state *h; if (entry == NULL) /* never happen, if metadata is consistent */ return (0); h = gfarm_hash_entry_data(entry); return ((h->flags & HOST_STATE_FLAG_RUNNABLE) != 0); }
/* * Return GFARM_ERR_NO_HOST, if there is a replica, but there isn't * any host which satisfies the hostname_filter. */ static char * search_idle_by_section_copy_info(struct gfarm_hash_table *hosts_state, int ncopies, struct gfarm_file_section_copy_info *copies, struct string_filter *hostname_filter, int nohosts, char **ohosts) { char *e; int i, nhosts; struct section_copy_info_array_iterator copy_iterator; struct gfarm_hash_entry *entry; struct search_idle_host_state *h; nhosts = 0; for (i = 0; i < ncopies; i++) { if ((*hostname_filter->suitable)(hostname_filter, copies[i].hostname)) nhosts++; } if (nhosts == 0) return (GFARM_ERR_NO_HOST); e = search_idle_cyclic(hosts_state, nhosts, hostname_filter, init_section_copy_info_array_iterator(©_iterator, copies), nohosts, ohosts); if (e == NULL) { e = gfarm_fixedstrings_dup(nohosts, ohosts, ohosts); if (e == NULL) { /* increase the load average of scheduled hosts */ for (i = 0; i < nohosts; i++) { entry = gfarm_hash_lookup(hosts_state, ohosts[i], strlen(ohosts[i]) + 1); if (entry == NULL) continue; /* shouldn't happen */ h = gfarm_hash_entry_data(entry); h->loadavg += VIRTUAL_LOAD_FOR_SCHEDULED_HOST; } } } return (e); }
static char * cache_path_info_get(const char *pathname, struct gfarm_path_info *info) { struct gfarm_hash_entry *he; int pathlen; struct path_info_cache *pic; struct timeval now; if (!cache_path_info_init()) return (GFARM_PATH_INFO_CACHE_CANCEL); pathlen = strlen(pathname); he = gfarm_hash_lookup(cache_table, pathname, pathlen); if (he != NULL) { pic = gfarm_hash_entry_data(he); if (pic != NULL) { /* check term of validity */ gettimeofday(&now, NULL); gfarm_timeval_sub(&now, &pic->time); if (gfarm_timeval_cmp(&now, &cache_timeout) >= 0) { _debug("! expire path_info cache: %s\n", pathname); #if 1 /* purge */ if (pic->noent == CACHE_SET) gfarm_path_info_free(&pic->info); if (gfarm_hash_purge(cache_table, pathname, strlen(pathname))) current_cache_num--; #endif return "expired path_info cache content"; } _debug("! use path_info cache: %s\n", pathname); if (pic->noent == CACHE_NOENT) /* NOENT cache */ return (GFARM_ERR_NO_SUCH_OBJECT); return gfarm_path_info_dup(&pic->info, info); } } return "cache_path_info_get: no path_info cache"; }
gfarm_error_t gfp_conn_hash_lookup(struct gfarm_hash_table **hashtabp, int hashtabsize, const char *hostname, int port, const char *username, struct gfarm_hash_entry **entry_ret) { gfarm_error_t e; struct gfp_conn_hash_id id; struct gfarm_hash_entry *entry; if (*hashtabp == NULL && (e = gfp_conn_hash_table_init(hashtabp, hashtabsize)) != GFARM_ERR_NO_ERROR) return (e); id.hostname = (char *)hostname; /* UNCONST */ id.port = port; id.username = (char *)username; /* UNCONST */ entry = gfarm_hash_lookup(*hashtabp, &id, sizeof(id)); if (entry == NULL) return (GFARM_ERR_NO_SUCH_OBJECT); *entry_ret = entry; return (GFARM_ERR_NO_ERROR); }
/* * if (op != GFARM_INODE_CREATE), (is_dir) may be -1, * and that means "don't care". */ char * lookup_node(struct node *parent, const char *name, int len, int is_dir, enum gfarm_node_lookup_op op, struct node **np) { struct gfarm_hash_entry *entry; int created, already_purged; struct node *n; if ((parent->flags & NODE_FLAG_IS_DIR) == 0) return (GFARM_ERR_NOT_A_DIRECTORY); if (len == 0) { /* We don't handle GFARM_INODE_MARK for this case */ if (op == GFARM_INODE_REMOVE) return (GFARM_ERR_INVALID_ARGUMENT); *np = parent; return (NULL); } else if (len == 1 && name[0] == '.') { /* We don't handle GFARM_INODE_MARK for this case */ if (op == GFARM_INODE_REMOVE) return (GFARM_ERR_INVALID_ARGUMENT); *np = parent; return (NULL); } else if (len == 2 && name[0] == '.' && name[1] == '.') { /* We don't handle GFARM_INODE_MARK for this case */ if (op == GFARM_INODE_REMOVE) return (GFARM_ERR_DIRECTORY_NOT_EMPTY); *np = parent->parent; return (NULL); } if (len > GFS_MAXNAMLEN) len = GFS_MAXNAMLEN; if (op == GFARM_INODE_MARK) { entry = gfarm_hash_lookup(parent->u.d.children, name, len); /* We should not honor the PURGED flag here */ if (entry != NULL) { n = gfarm_hash_entry_data(entry); if ((n->flags & NODE_FLAG_IS_DIR) == is_dir) { /* abandon the PURGED flag at the mark phase */ n->flags &= ~NODE_FLAG_PURGED; n->flags |= NODE_FLAG_MARKED; *np = n; return (NULL); } if (opendir_count > 0) { if (is_dir) { change_file_node_to_dir(n); } else { recursive_delayed_purge_nodes(n); change_dir_node_to_file(n); } /* abandon the PURGED flag at the mark phase */ n->flags &= ~NODE_FLAG_PURGED; n->flags |= NODE_FLAG_MARKED; *np = n; return (NULL); } recursive_free_nodes(n); gfarm_hash_purge(parent->u.d.children, name, len); } /* do create */ } else if (op != GFARM_INODE_CREATE) { entry = gfarm_hash_lookup(parent->u.d.children, name, len); if (entry == NULL) return (GFARM_ERR_NO_SUCH_OBJECT); n = gfarm_hash_entry_data(entry); already_purged = (n->flags & NODE_FLAG_PURGED) != 0; if (already_purged || op == GFARM_INODE_REMOVE) { if (opendir_count > 0) { recursive_delayed_purge_nodes(n); } else { recursive_free_nodes(n); gfarm_hash_purge(parent->u.d.children, name, len); } if (already_purged) return (GFARM_ERR_NO_SUCH_OBJECT); *np = NULL; return (NULL); } *np = n; return (NULL); } entry = gfarm_hash_enter(parent->u.d.children, name, len, #if 0 is_dir ? DIR_NODE_SIZE : FILE_NODE_SIZE, #else /* * always allocate DIR_NODE_SIZE * to make it possible to change a file to a dir */ DIR_NODE_SIZE, #endif &created); if (entry == NULL) return (GFARM_ERR_NO_MEMORY); n = gfarm_hash_entry_data(entry); if (!created) { n->flags &= ~NODE_FLAG_PURGED; /* assert(op == GFARM_INODE_CREATE); */ *np = n; return (NULL); } if (is_dir) init_dir_node(n, name, len); else init_file_node(n, name, len); n->parent = parent; if (op == GFARM_INODE_MARK) n->flags |= NODE_FLAG_MARKED; *np = n; return (NULL); }
static gfarm_error_t create_filelist(char *file, struct gfs_stat *st, void *arg) { struct flist *a = arg; int i, j, ncopy, src_ncopy = 0, dst_ncopy = 0; char **copy; gfarm_error_t e; if (!GFARM_S_ISREG(st->st_mode)) { if (opt_verbose) printf("%s: not a regular file, skipped\n", file); return (GFARM_ERR_NO_ERROR); } e = gfs_replica_list_by_name(file, &ncopy, ©); if (e != GFARM_ERR_NO_ERROR) return (e); /* if there is no available file replica, display error message */ if (ncopy == 0 && st->st_size > 0) { fprintf(stderr, "%s: no available file repilca\n", file); e = GFARM_ERR_NO_ERROR; goto free_copy; } for (i = 0; i < ncopy; ++i) { if ((a->src_hosthash == NULL || gfarm_hash_lookup( a->src_hosthash, copy[i], strlen(copy[i]) + 1)) && gfarm_host_is_in_domain(copy[i], a->src_domain)) { ++src_ncopy; } if ((a->dst_hosthash == NULL || gfarm_hash_lookup( a->dst_hosthash, copy[i], strlen(copy[i]) + 1)) && gfarm_host_is_in_domain(copy[i], a->dst_domain)) { ++dst_ncopy; } } /* * if there is no replica in a set of source nodes or there * are already specified number of replicas in a set of * destination nodes, do not add. */ if (src_ncopy == 0 || dst_ncopy == opt_nrep) { e = GFARM_ERR_NO_ERROR; goto free_copy; } /* add source nodes to srchash to count the number of source nodes */ for (i = 0; i < ncopy; ++i) { char *s = copy[i]; if ((a->src_hosthash == NULL || gfarm_hash_lookup( a->src_hosthash, s, strlen(s) + 1)) && gfarm_host_is_in_domain(s, a->src_domain)) gfarm_hash_enter(a->srchash, s, strlen(s)+1, 0, NULL); } /* add a file info to slist */ for (j = 0; j < opt_nrep - dst_ncopy; ++j) { e = gfarm_list_add_file_info(file, st->st_size, ncopy, copy, 0, &a->slist); if (e != GFARM_ERR_NO_ERROR) goto free_copy; } /* add a file info to dlist if too many file replicas exist */ if (dst_ncopy > opt_nrep) { e = gfarm_list_add_file_info(file, st->st_size, ncopy, copy, dst_ncopy - opt_nrep, &a->dlist); } free_copy: gfarm_strings_free_deeply(ncopy, copy); return (e); }
static char * search_idle(int concurrency, int enough_number, struct gfarm_hash_table *hosts_state, int nihosts, struct string_filter *ihost_filter, struct get_next_iterator *ihost_iterator, int *nohostsp, char **ohosts) { char *e, *ihost; int i, rv, desired_number = *nohostsp; struct search_idle_state s; struct gfarm_hash_entry *entry; struct search_idle_host_state *h; struct search_idle_callback_closure *c; struct sockaddr addr; struct gfs_client_get_load_state *gls; if (nihosts == 0) return (GFARM_ERR_NO_HOST); s.q = gfarm_eventqueue_alloc(); if (s.q == NULL) return (GFARM_ERR_NO_MEMORY); s.available_hosts_number = s.idle_hosts_number = s.semi_idle_hosts_number = 0; s.available_hosts = malloc(nihosts * sizeof(*s.available_hosts)); if (s.available_hosts == NULL) { gfarm_eventqueue_free(s.q); return (GFARM_ERR_NO_MEMORY); } s.concurrency = 0; for (i = 0; i < nihosts; i++) { do { ihost = (*ihost_iterator->get_next)(ihost_iterator); } while (!(*ihost_filter->suitable)(ihost_filter, ihost)); entry = gfarm_hash_lookup(hosts_state, ihost, strlen(ihost) + 1); if (entry == NULL) continue; /* never happen, if metadata is consistent */ h = gfarm_hash_entry_data(entry); if ((h->flags & HOST_STATE_FLAG_LOADAVG_TRIED) != 0) { if ((h->flags & (default_search_method == GFARM_SCHEDULE_SEARCH_BY_LOADAVG ? HOST_STATE_FLAG_LOADAVG_AVAIL : HOST_STATE_FLAG_AUTH_SUCCEED)) != 0) search_idle_record_host(&s, h, ihost); } else { e = gfarm_host_info_address_get(ihost, gfarm_spool_server_port, h->host_info, &addr, NULL); if (e != NULL) continue; /* We limit concurrency here */ rv = 0; while (s.concurrency >= concurrency) { rv = gfarm_eventqueue_turn(s.q, NULL); /* XXX - how to report this error? */ if (rv != 0 && rv != EAGAIN && rv != EINTR) break; } if (rv != 0 && rv != EAGAIN && rv != EINTR) break; c = malloc(sizeof(*c)); if (c == NULL) break; c->state = &s; c->peer_addr = addr; c->ah.host_state = h; c->ah.hostname = ihost; /* record return value */ h->flags |= HOST_STATE_FLAG_LOADAVG_TRIED; e = gfs_client_get_load_request_multiplexed(s.q, &c->peer_addr, default_search_method == GFARM_SCHEDULE_SEARCH_BY_LOADAVG ? search_idle_load_callback : search_idle_load_and_connect_callback, c, &gls); if (e != NULL) { free(c); } else { c->protocol_state = gls; s.concurrency++; } } if (s.idle_hosts_number >= desired_number || s.semi_idle_hosts_number >= enough_number) break; } /* XXX - how to report this error? */ rv = gfarm_eventqueue_loop(s.q, NULL); gfarm_eventqueue_free(s.q); if (s.available_hosts_number == 0) { free(s.available_hosts); *nohostsp = 0; return (GFARM_ERR_NO_HOST); } /* sort hosts in the order of load average */ qsort(s.available_hosts, s.available_hosts_number, sizeof(*s.available_hosts), loadavg_compare); for (i = 0; i < s.available_hosts_number && i < desired_number; i++) ohosts[i] = s.available_hosts[i].hostname; /* return value */ *nohostsp = i; free(s.available_hosts); return (NULL); }