void dlist_add_back(struct dlist *l, void *ptr) { // create the node to be added in struct dnode *new_node = dnode_create(); dnode_setdata(new_node, ptr); // update pointers if (!l->counter) { // list is empty l->front = l->back = new_node; new_node->next = new_node->prev = NULL; } else { struct dnode *n = l->back; new_node->prev = n; new_node->next = NULL; l->back->next = new_node; l->back = new_node; } l->counter++; #ifdef DEBUG printf("counter= %d, %s\n", l->counter, (char *) ptr); printf("front= %s\n", (char *) l->front->data); printf("back= %s\n\n", (char *) l->back->data); #endif /* DEBUG */ }
/// Add a new PathAction into the specified CmdAction. /// No coalescing is attempted - PA objects are are always added /// here unless they are truly identical (same pointer == same object). /// @param[in] ca the CA object pointer /// @param[in] pa the PA object pointer void ca_record_pa(ca_o ca, pa_o pa) { dnode_t *dnp; _ca_verbosity_pa(pa, ca, "RECORDING"); // All data is in the key - that's why the value can be null. if (!(dnp = dnode_create(NULL))) { putil_syserr(2, "dnode_create()"); } dict_insert(ca->ca_raw_pa_dict, dnp, pa); }
static void construct(dict_t *d) { input_t in; int done = 0; dict_load_t dl; dnode_t *dn; char *tok1, *tok2, *val; const char *key; char *help = "p turn prompt on\n" "q finish construction\n" "a <key> <val> add new entry\n"; if (!dict_isempty(d)) puts("warning: dictionary not empty!"); dict_load_begin(&dl, d); while (!done) { if (prompt) putchar('>'); fflush(stdout); if (!fgets(in, sizeof(input_t), stdin)) break; switch (in[0]) { case '?': puts(help); break; case 'p': prompt = 1; break; case 'q': done = 1; break; case 'a': if (tokenize(in+1, &tok1, &tok2, (char **) 0) != 2) { puts("what?"); break; } key = dupstring(tok1); val = dupstring(tok2); dn = dnode_create(val); if (!key || !val || !dn) { puts("out of memory"); free((void *) key); free(val); if (dn) dnode_destroy(dn); } dict_load_next(&dl, dn, key); break; default: putchar('?'); putchar('\n'); break; } } dict_load_end(&dl); }
/// Convert all raw PAs in the group into a single set of "cooked" PAs /// under the leader. /// @param[in] ca the object pointer void ca_coalesce(ca_o ca) { dict_t *dict_raw, *dict_cooked; dnode_t *dnpr, *dnpc, *next; dict_raw = ca->ca_raw_pa_dict; assert(!ca->ca_cooked_pa_dict); if ((dict_cooked = dict_create(DICTCOUNT_T_MAX, pa_cmp_by_pathname))) { ca->ca_cooked_pa_dict = dict_cooked; } else { putil_syserr(2, "dict_create()"); } for (dnpr = dict_first(dict_raw); dnpr;) { pa_o raw_pa, ckd_pa; next = dict_next(dict_raw, dnpr); raw_pa = (pa_o)dnode_getkey(dnpr); _ca_verbosity_pa(raw_pa, ca, "COALESCING"); // All data is in the key - that's why the value can be null. if ((dnpc = dict_lookup(dict_cooked, raw_pa))) { int keep_cooked = 0; ckd_pa = (pa_o)dnode_getkey(dnpc); if (!pa_is_read(raw_pa) && !pa_is_read(ckd_pa)) { moment_s raw_timestamp, ckd_timestamp; // If they're both destructive ops (non-read) then we // need to consider timestamps and use the later one. if (pa_has_timestamp(raw_pa) && pa_has_timestamp(ckd_pa)) { // If the PA's have their own timestamps, use them. raw_timestamp = pa_get_timestamp(raw_pa); ckd_timestamp = pa_get_timestamp(ckd_pa); } else { // Otherwise key off the file times. This is for // support of "dummy" PAs as used in shopping. raw_timestamp = pa_get_moment(raw_pa); ckd_timestamp = pa_get_moment(ckd_pa); } if (moment_cmp(raw_timestamp, ckd_timestamp, NULL) <= 0) { // Cooked write op is newer and can stay. keep_cooked = 1; } } else if (pa_is_read(raw_pa)) { // There's no point replacing a read with another read, // so regardless of whether the current cooked PA is a // read or write, it can stay. keep_cooked = 1; } else { // A write always beats a read. } if (!keep_cooked) { dict_delete(dict_cooked, dnpc); dnode_destroy(dnpc); _ca_verbosity_pa(ckd_pa, ca, "REMOVING"); pa_destroy(ckd_pa); if (!(dnpc = dnode_create(NULL))) { putil_syserr(2, "dnode_create()"); } ckd_pa = pa_copy(raw_pa); dict_insert(dict_cooked, dnpc, ckd_pa); } } else { if (!(dnpc = dnode_create(NULL))) { putil_syserr(2, "dnode_create()"); } ckd_pa = pa_copy(raw_pa); dict_insert(dict_cooked, dnpc, ckd_pa); } // Clean up the raw set as we move PAs to the cooked one. dict_delete(dict_raw, dnpr); dnode_destroy(dnpr); dnpr = next; } return; }