// remove expired items from connection_list void _hp_clean_expired(hashtable_t *ht, time_t max_age) { hashtable_item_t *i; _connection_info_t *ci; _connection_list_t *cl; strlist_t *rl = 0; strlist_iterator_t *rli; char *tip; for (ht_reset(ht); ht_hasnext(ht); ) { i = ht_next(ht); ci = (_connection_info_t*) i->value; // remove expired connection times ci->connects = _hp_cl_remove(ci->connects, max_age); // if there are none left, remove the ip from the table. if (_hp_cl_size(ci->connects) < 1) rl = str_add(rl, ci->ip); } // remove ips with no connection-times from hashtable. for (rli = str_iterator(rl); str_iterator_hasnext(rli); ) { tip = str_iterator_next(rli); // printf("DEBUG: expiring %s\n", tip); ht_remove(ht, tip); } str_close(rl); free(rli); }
/* * This is called at the beginning of a cubist run to clear out * all "files" generated on the previous run and to prepare it * for the next run. */ void rbm_removeall() { /* Check if there actually is anything to remove */ if (strbufv != NULL) { /* * Destroy all STRBUF's in the hash table. * Note that this loop leaves the hash table full of * pointers to deallocated STRBUF's until ht_destroy * is called below. */ ht_reset(strbufv); /* just in case */ while (1) { void *e = ht_next(strbufv); if (e == NULL) break; strbuf_destroy((STRBUF *) ht_value(e)); } /* Destroy the hash table itself */ ht_destroy(strbufv); } /* Create/recreate the hash table for subsequent use */ strbufv = ht_new(HASH_LEN); }
int hitlist_init(void) { var_t *hitlist; ht_t *config; ht_pos_t pos; var_t *v; hitlist = cf_get(VT_TABLE, HITLIST_NAME, NULL); if (hitlist == NULL) { log_notice("hitlist_init: no lists configured"); return 0; } hitlists = sht_create(BUCKETS, free); if (hitlists == NULL) { log_die(EX_SOFTWARE, "hitlist_init: sht_create failed"); } config = hitlist->v_data; ht_start(config, &pos); while ((v = ht_next(config, &pos))) { if (hitlist_register(v->v_name)) { log_error("hitlist_init: hitlist_register failed"); return -1; } } return 0; }
// shows state. void hp_show_state(hashtable_t *ht, int timeout_seconds, int (*prnf)(char *fmt, ...)) { time_t now; hashtable_item_t *i; _connection_info_t *ci; _connection_list_t *cl; now = time(0); now -= timeout_seconds; for (ht_reset(ht); ht_hasnext(ht); ) { i = ht_next(ht); ci = (_connection_info_t*) i->value; prnf("info: %s\n", ci->ip); for (cl = ci->connects; cl; cl = cl->next) prnf(" %d, ttl = %d\n", cl->time, cl->time - now); prnf("\n"); } }
static void json_dump_L(JSON *v, int L) { char buffer[256]; switch(v->type) { case j_string: { printf("\"%s\"", json_escape(v->value, buffer, sizeof buffer)); } break; case j_number: printf("%s", (const char *)v->value); break; case j_object: { Hash_Tbl *h = v->value; const char *key = ht_next (h, NULL); puts("{"); while(key) { printf("%*c\"%s\" : ", L*2 + 1, ' ', json_escape(key, buffer, sizeof buffer)); json_dump_L(ht_get(h, key), L + 1); key = ht_next(h, key); if(key) puts(","); } printf("}"); } break; case j_array: { JSON *m = v->value; puts("["); while(m) { printf("%*c", L*2, ' '); json_dump_L(m, L + 1); m = m->next; if(m) puts(","); } printf("]"); } break; case j_true: { printf("true"); } break; case j_false: { printf("false"); } break; case j_null: { printf("null"); } break; default: break; } }
struct ht_node * ht_values_as_vector(struct ht_ht *ht) { struct ht_node *v = malloc(ht->items*sizeof(struct ht_node)); struct ht_node *n = ht_first(ht); for (int i = 0; i < ht->items; i++) { v[i] = *n; n = ht_next(ht); } return v; }
// Tarjan's Algorithm from wikipedia static uint32_t strongly_connected(struct stack* stack, remodel_node_t* node, uint32_t* index) { node->index = *index; node->low_index = *index; (*index)++; stack_push(stack, node); ht_entry_t* entry; ht_iterator_t iter = HT_ITERATOR_INITIALIZER; while (ht_next(node->children, &iter, &entry)) { remodel_edge_t* edge = entry->value; assert(edge->from == node); if (edge->to->index == 0) { strongly_connected(stack, edge->to, index); node->low_index = min(node->low_index, edge->to->low_index); } else if(stack_contains(stack, edge->to)) { node->low_index = min(node->low_index, edge->to->index); } } if (node->low_index == node->index) { array_t* component = array_new(); remodel_node_t* w; do { assert(!stack_is_empty(stack)); w = stack_pop(stack); array_append(component, w); } while (w != node); if (component->len > 1) { fprintf(stderr, "error: dependency graph contains cycle:\n"); fprintf(stderr, " ["); for (uint32_t i = 0; i < component->len; i++) { remodel_node_t* n = array_get(component, i); fprintf(stderr, "%s", n->name); if (i != component->len - 1) { fprintf(stderr, ", "); } } fprintf(stderr, "]\n"); array_free(component); return true; } else { array_free(component); return false; } } else { return false; } }
void write_frequencies (int fl, char *buffer, long buflen) { struct ht_ht *ht; long total, i, j, size; struct ht_node *nd; sorter *s; sorter tmp; ht = generate_frequencies (fl, buffer, buflen); total = 0; size = 0; for (nd = ht_first (ht); nd != NULL; nd = ht_next (ht)) { total = total + nd->val; size++; } s = calloc (size, sizeof (sorter)); i = 0; for (nd = ht_first (ht); nd != NULL; nd = ht_next (ht)) { s[i].string = nd->key; s[i++].num = nd->val; } for (i = 0; i < size - 1; i++) for (j = i + 1; j < size; j++) if (s[i].num < s[j].num) { memcpy (&tmp, &(s[i]), sizeof (sorter)); memcpy (&(s[i]), &(s[j]), sizeof (sorter)); memcpy (&(s[j]), &tmp, sizeof (sorter)); } for (i = 0; i < size; i++) printf ("%s %.3f\n", s[i].string, 100 * (float) s[i].num / total); printf ("\n"); ht_destroy (ht); free (s); }
void dump_symbol_table_info(void) { int size, elem, collide, maxcollide; ht_get_info(&s_symbol_table, &size, &elem, &collide, &maxcollide); printf("symbol table: %d %d %d %d\n", size, elem, collide, maxcollide); { HashIterator it; HashEntry* e; for (e = ht_begin(&it, &s_symbol_table); e != NULL; e = ht_next(&it)) { Symbol* sym = (Symbol*)e->val; printf("%4d %08x: %s\n", it.idx, e->hash, sym->name); } } }
static void validate_detect_cycles(remodel_graph_t* graph) { struct stack* stack = stack_new(ht_count(graph->nodes)); uint32_t index = 1; bool has_cycle = false; ht_entry_t* entry; ht_iterator_t iter = HT_ITERATOR_INITIALIZER; while (ht_next(graph->nodes, &iter, &entry)) { remodel_node_t* node = entry->value; if (node->index == 0) { has_cycle |= strongly_connected(stack, node, &index); } } if (has_cycle) { fprintf(stderr, "dependency graph has a cycle, exiting...\n"); exit(1); } stack_free(stack); }
/* * Returns the list of pre groups from config. * */ strlist_t * groups_find_all() { strlist_t * l = 0; char *tmp, buf[300], *grp; hashtable_t *cfg = get_config(); hashtable_t *env = get_context(); hashtable_item_t *htn; // check if we have made it already. if (ht_get(env, "ALLGROUPS")) return (strlist_t*)ht_get(env, "ALLGROUPS"); ht_reset(cfg); // look through all properties in config. while (htn = ht_next(cfg)) { tmp = htn->key; if (strcmp(tmp, "group.")) continue; grp = strdup(tmp + 6); tmp = strchr(grp, '.'); if (!tmp) { free(grp); continue; } *tmp = 0; if (!str_search(l, grp, 0)) { l = str_add(l, grp); } } ht_put_obj(env, "ALLGROUPS", l); return l; }
HashEntry* ht_begin(HashIterator* it, HashTable* ht) { it->ht = ht; it->idx = -1; it->p = NULL; return ht_next(it); }
int main(int argc, char** argv) { char* remodel_file; uint32_t num_threads = DEFAULT_NUM_THREADS; bool generate_graph = false; int c; while ((c = getopt(argc, argv, "h:v:p:g")) != -1) { switch (c) { case 'h': fprintf(stderr, USAGE, argv[0]); exit(0); case 'v': fprintf(stderr, "Remodel: %s\n", version); break; case 'p': num_threads = (uint32_t)atoi(optarg); break; case 'g': generate_graph = true; break; default: fprintf(stderr, USAGE, argv[0]); exit(1); } } // The project suggests that we take a production instead of a remodel file here. // That doesn't make sense in this implementation for a few reasons: // 1. When executing the production correctly, the only thing we can guarantee // is that we will execute the production. We cannot guarantee that the // production will be the only thing executed (if it has children who // need rebuilding) or that a non-descendent won't be executed (if it a // parent of the production was modified, or a cousin of the production, // etc...). We probably could guarantee that only the component of the graph // containing the production would be executed, but that seems like more // trouble than its worth, except in unusual systems with many // unrelated components. // 2. We allow multiple productions in a rule, and it's unclear // what the correct behavior for a production is: is it when the LHS // literally matches the supplied production, when the files on the LHS // are the same as the files on the RHS, or when a file in the production // is contained in the LHS? What about when multiple productions // are supplied? // Also, it was useful for testing to be able to supply different remodel files. if (optind < argc) { remodel_file = argv[optind]; optind++; } else { remodel_file = "build.remodel"; } remodel_graph_t* graph = remodel_load_file(remodel_file); validate_graph(graph); if (generate_graph) { printf("digraph g {\n"); ht_entry_t* entry; ht_iterator_t iter = HT_ITERATOR_INITIALIZER; while (ht_next(graph->nodes, &iter, &entry)) { remodel_node_t* parent = entry->value; ht_entry_t* child_entry; ht_iterator_t child_iter = HT_ITERATOR_INITIALIZER; while (ht_next(parent->children, &child_iter, &child_entry)) { remodel_edge_t* edge = child_entry->value; printf("\t\"%s\" -> \"%s\"", parent->name, edge->to->name); if (edge->command) { printf(" [label=\"%s\"]", edge->command); } printf(";\n"); } } printf("}\n"); } else { remodel_execute(graph, num_threads); } return 0; }