Commit 7ff5fdae authored by Rusty Russell's avatar Rusty Russell

Cleanup variable names.

struct op: serial -> seqnum (and drop use of term "serial" everywhere).
struct op: op -> type
struct op_desc: general replacement for file/op_num pair.
Change add_dependency to take two const op_desc *: means reshuffle since we can't adjust the args any more.
parent 83a91302
...@@ -126,8 +126,8 @@ enum op_type { ...@@ -126,8 +126,8 @@ enum op_type {
}; };
struct op { struct op {
unsigned int serial; unsigned int seqnum;
enum op_type op; enum op_type type;
TDB_DATA key; TDB_DATA key;
TDB_DATA data; TDB_DATA data;
int ret; int ret;
...@@ -152,6 +152,11 @@ struct op { ...@@ -152,6 +152,11 @@ struct op {
}; };
}; };
struct op_desc {
unsigned int file;
unsigned int op_num;
};
static unsigned char hex_char(const char *filename, unsigned int line, char c) static unsigned char hex_char(const char *filename, unsigned int line, char c)
{ {
c = toupper(c); c = toupper(c);
...@@ -188,13 +193,13 @@ static TDB_DATA make_tdb_data(const void *ctx, ...@@ -188,13 +193,13 @@ static TDB_DATA make_tdb_data(const void *ctx,
} }
static void add_op(const char *filename, struct op **op, unsigned int i, static void add_op(const char *filename, struct op **op, unsigned int i,
unsigned int serial, enum op_type type) unsigned int seqnum, enum op_type type)
{ {
struct op *new; struct op *new;
*op = talloc_realloc(NULL, *op, struct op, i+1); *op = talloc_realloc(NULL, *op, struct op, i+1);
new = (*op) + i; new = (*op) + i;
new->op = type; new->type = type;
new->serial = serial; new->seqnum = seqnum;
new->ret = 0; new->ret = 0;
new->group_start = 0; new->group_start = 0;
} }
...@@ -263,7 +268,7 @@ static void op_add_traversefn(const char *filename, ...@@ -263,7 +268,7 @@ static void op_add_traversefn(const char *filename,
op[op_num].key = tdb_null; op[op_num].key = tdb_null;
} }
/* <serial> tdb_store <rec> <rec> <flag> = <ret> */ /* <seqnum> tdb_store <rec> <rec> <flag> = <ret> */
static void op_add_store(const char *filename, static void op_add_store(const char *filename,
struct op op[], unsigned int op_num, char *words[]) struct op op[], unsigned int op_num, char *words[])
{ {
...@@ -278,7 +283,7 @@ static void op_add_store(const char *filename, ...@@ -278,7 +283,7 @@ static void op_add_store(const char *filename,
total_keys++; total_keys++;
} }
/* <serial> tdb_append <rec> <rec> = <rec> */ /* <seqnum> tdb_append <rec> <rec> = <rec> */
static void op_add_append(const char *filename, static void op_add_append(const char *filename,
struct op op[], unsigned int op_num, char *words[]) struct op op[], unsigned int op_num, char *words[])
{ {
...@@ -299,7 +304,7 @@ static void op_add_append(const char *filename, ...@@ -299,7 +304,7 @@ static void op_add_append(const char *filename,
total_keys++; total_keys++;
} }
/* <serial> tdb_get_seqnum = <ret> */ /* <seqnum> tdb_get_seqnum = <ret> */
static void op_add_seqnum(const char *filename, static void op_add_seqnum(const char *filename,
struct op op[], unsigned int op_num, char *words[]) struct op op[], unsigned int op_num, char *words[])
{ {
...@@ -363,7 +368,7 @@ static int op_find_start(struct op op[], unsigned int op_num, enum op_type type) ...@@ -363,7 +368,7 @@ static int op_find_start(struct op op[], unsigned int op_num, enum op_type type)
unsigned int i; unsigned int i;
for (i = op_num-1; i > 0; i--) { for (i = op_num-1; i > 0; i--) {
if (op[i].op == type && !op[i].group_len) if (op[i].type == type && !op[i].group_len)
return i; return i;
} }
return 0; return 0;
...@@ -461,10 +466,8 @@ struct depend { ...@@ -461,10 +466,8 @@ struct depend {
/* We can have more than one */ /* We can have more than one */
struct list_node pre_list; struct list_node pre_list;
struct list_node post_list; struct list_node post_list;
unsigned int needs_file; struct op_desc needs;
unsigned int needs_opnum; struct op_desc prereq;
unsigned int satisfies_file;
unsigned int satisfies_opnum;
}; };
static void check_deps(const char *filename, struct op op[], unsigned int num) static void check_deps(const char *filename, struct op op[], unsigned int num)
...@@ -484,11 +487,11 @@ static void dump_pre(char *filename[], struct op *op[], ...@@ -484,11 +487,11 @@ static void dump_pre(char *filename[], struct op *op[],
struct depend *dep; struct depend *dep;
printf("%s:%u (%u) still waiting for:\n", filename[file], i+1, printf("%s:%u (%u) still waiting for:\n", filename[file], i+1,
op[file][i].serial); op[file][i].seqnum);
list_for_each(&op[file][i].pre, dep, pre_list) list_for_each(&op[file][i].pre, dep, pre_list)
printf(" %s:%u (%u)\n", printf(" %s:%u (%u)\n",
filename[dep->satisfies_file], dep->satisfies_opnum+1, filename[dep->prereq.file], dep->prereq.op_num+1,
op[dep->satisfies_file][dep->satisfies_opnum].serial); op[dep->prereq.file][dep->prereq.op_num].seqnum);
check_deps(filename[file], op[file], i); check_deps(filename[file], op[file], i);
} }
...@@ -525,8 +528,8 @@ static bool do_pre(struct tdb_context *tdb, ...@@ -525,8 +528,8 @@ static bool do_pre(struct tdb_context *tdb,
#if DEBUG_DEPS #if DEBUG_DEPS
printf("%s:%u:got pre %u from %s:%u\n", filename[file], i+1, printf("%s:%u:got pre %u from %s:%u\n", filename[file], i+1,
dep->needs_opnum+1, filename[dep->satisfies_file], dep->needs.op_num+1, filename[dep->prereq.file],
dep->satisfies_opnum+1); dep->prereq.op_num+1);
fflush(stdout); fflush(stdout);
#endif #endif
/* This could be any op, not just this one. */ /* This could be any op, not just this one. */
...@@ -543,12 +546,12 @@ static void do_post(char *filename[], struct op *op[], ...@@ -543,12 +546,12 @@ static void do_post(char *filename[], struct op *op[],
list_for_each(&op[file][i].post, dep, post_list) { list_for_each(&op[file][i].post, dep, post_list) {
#if DEBUG_DEPS #if DEBUG_DEPS
printf("%s:%u:sending to file %s:%u\n", filename[file], i+1, printf("%s:%u:sending to file %s:%u\n", filename[file], i+1,
filename[dep->needs_file], dep->needs_opnum+1); filename[dep->needs.file], dep->needs.op_num+1);
#endif #endif
if (write(pipes[dep->needs_file].fd[1], &dep, sizeof(dep)) if (write(pipes[dep->needs.file].fd[1], &dep, sizeof(dep))
!= sizeof(dep)) != sizeof(dep))
err(1, "%s:%u failed to tell file %s", err(1, "%s:%u failed to tell file %s",
filename[file], i+1, filename[dep->needs_file]); filename[file], i+1, filename[dep->needs.file]);
} }
} }
...@@ -591,7 +594,7 @@ static int nontrivial_traverse(struct tdb_context *tdb, ...@@ -591,7 +594,7 @@ static int nontrivial_traverse(struct tdb_context *tdb,
"traverse did not terminate"); "traverse did not terminate");
} }
if (tinfo->op[tinfo->file][tinfo->i].op != OP_TDB_TRAVERSE) if (tinfo->op[tinfo->file][tinfo->i].type != OP_TDB_TRAVERSE)
fail(tinfo->filename[tinfo->file], tinfo->start + 1, fail(tinfo->filename[tinfo->file], tinfo->start + 1,
"%s:%u:traverse terminated early"); "%s:%u:traverse terminated early");
...@@ -605,7 +608,7 @@ static int nontrivial_traverse(struct tdb_context *tdb, ...@@ -605,7 +608,7 @@ static int nontrivial_traverse(struct tdb_context *tdb,
avoid_deadlock); avoid_deadlock);
/* We backed off, or we hit OP_TDB_TRAVERSE_END. */ /* We backed off, or we hit OP_TDB_TRAVERSE_END. */
if (tinfo->op[tinfo->file][tinfo->i].op != OP_TDB_TRAVERSE) if (tinfo->op[tinfo->file][tinfo->i].type != OP_TDB_TRAVERSE)
return 1; return 1;
return 0; return 0;
...@@ -629,7 +632,7 @@ static unsigned op_traverse(struct tdb_context *tdb, ...@@ -629,7 +632,7 @@ static unsigned op_traverse(struct tdb_context *tdb,
* original traverse went A (delete A), B, we might do B * original traverse went A (delete A), B, we might do B
* (delete A). So if we have ops left over, we do it now. */ * (delete A). So if we have ops left over, we do it now. */
while (tinfo.i != start + op[file][start].group_len) { while (tinfo.i != start + op[file][start].group_len) {
if (op[file][tinfo.i].op == OP_TDB_TRAVERSE) if (op[file][tinfo.i].type == OP_TDB_TRAVERSE)
tinfo.i++; tinfo.i++;
else else
tinfo.i = run_ops(tdb, pre_fd, filename, op, file, tinfo.i = run_ops(tdb, pre_fd, filename, op, file,
...@@ -665,7 +668,7 @@ unsigned run_ops(struct tdb_context *tdb, ...@@ -665,7 +668,7 @@ unsigned run_ops(struct tdb_context *tdb,
if (!do_pre(tdb, filename, op, file, pre_fd, i, backoff)) if (!do_pre(tdb, filename, op, file, pre_fd, i, backoff))
return i; return i;
switch (op[file][i].op) { switch (op[file][i].type) {
case OP_TDB_LOCKALL: case OP_TDB_LOCKALL:
try(tdb_lockall(tdb), op[file][i].ret); try(tdb_lockall(tdb), op[file][i].ret);
break; break;
...@@ -805,7 +808,7 @@ static struct op *maybe_cancel_transaction(const char *filename, ...@@ -805,7 +808,7 @@ static struct op *maybe_cancel_transaction(const char *filename,
if (start) { if (start) {
char *words[] = { "<unknown>", "tdb_close", NULL }; char *words[] = { "<unknown>", "tdb_close", NULL };
add_op(filename, &op, *num, op[start].serial, add_op(filename, &op, *num, op[start].seqnum,
OP_TDB_TRANSACTION_CANCEL); OP_TDB_TRANSACTION_CANCEL);
op_analyze_transaction(filename, op, *num, words); op_analyze_transaction(filename, op, *num, words);
(*num)++; (*num)++;
...@@ -845,7 +848,7 @@ static struct op *load_tracefile(const char *filename, unsigned int *num, ...@@ -845,7 +848,7 @@ static struct op *load_tracefile(const char *filename, unsigned int *num,
words = strsplit(lines, lines[i], " ", NULL); words = strsplit(lines, lines[i], " ", NULL);
if (!words[0] || !words[1]) if (!words[0] || !words[1])
fail(filename, i+1, "Expected serial number and op"); fail(filename, i+1, "Expected seqnum number and op");
opt = find_keyword(words[1], strlen(words[1])); opt = find_keyword(words[1], strlen(words[1]));
if (!opt) { if (!opt) {
...@@ -873,15 +876,10 @@ static struct op *load_tracefile(const char *filename, unsigned int *num, ...@@ -873,15 +876,10 @@ static struct op *load_tracefile(const char *filename, unsigned int *num,
} }
/* We remember all the keys we've ever seen, and who has them. */ /* We remember all the keys we've ever seen, and who has them. */
struct key_user {
unsigned int file;
unsigned int op_num;
};
struct keyinfo { struct keyinfo {
TDB_DATA key; TDB_DATA key;
unsigned int num_users; unsigned int num_users;
struct key_user *user; struct op_desc *user;
}; };
static const TDB_DATA must_not_exist; static const TDB_DATA must_not_exist;
...@@ -893,7 +891,7 @@ static const TDB_DATA not_exists_or_empty; ...@@ -893,7 +891,7 @@ static const TDB_DATA not_exists_or_empty;
* not exist, otherwise the data it needs. */ * not exist, otherwise the data it needs. */
static const TDB_DATA *needs(const struct op *op) static const TDB_DATA *needs(const struct op *op)
{ {
switch (op->op) { switch (op->type) {
/* FIXME: Pull forward deps, since we can deadlock */ /* FIXME: Pull forward deps, since we can deadlock */
case OP_TDB_CHAINLOCK: case OP_TDB_CHAINLOCK:
case OP_TDB_CHAINLOCK_NONBLOCK: case OP_TDB_CHAINLOCK_NONBLOCK:
...@@ -957,14 +955,14 @@ static const TDB_DATA *needs(const struct op *op) ...@@ -957,14 +955,14 @@ static const TDB_DATA *needs(const struct op *op)
return &must_exist; return &must_exist;
default: default:
errx(1, "Unexpected op %i", op->op); errx(1, "Unexpected op type %i", op->type);
} }
} }
static bool starts_transaction(const struct op *op) static bool starts_transaction(const struct op *op)
{ {
return op->op == OP_TDB_TRANSACTION_START; return op->type == OP_TDB_TRANSACTION_START;
} }
static bool in_transaction(const struct op op[], unsigned int i) static bool in_transaction(const struct op op[], unsigned int i)
...@@ -975,13 +973,13 @@ static bool in_transaction(const struct op op[], unsigned int i) ...@@ -975,13 +973,13 @@ static bool in_transaction(const struct op op[], unsigned int i)
static bool successful_transaction(const struct op *op) static bool successful_transaction(const struct op *op)
{ {
return starts_transaction(op) return starts_transaction(op)
&& op[op->group_len].op == OP_TDB_TRANSACTION_COMMIT; && op[op->group_len].type == OP_TDB_TRANSACTION_COMMIT;
} }
static bool starts_traverse(const struct op *op) static bool starts_traverse(const struct op *op)
{ {
return op->op == OP_TDB_TRAVERSE_START return op->type == OP_TDB_TRAVERSE_START
|| op->op == OP_TDB_TRAVERSE_READ_START; || op->type == OP_TDB_TRAVERSE_READ_START;
} }
static bool in_traverse(const struct op op[], unsigned int i) static bool in_traverse(const struct op op[], unsigned int i)
...@@ -991,7 +989,8 @@ static bool in_traverse(const struct op op[], unsigned int i) ...@@ -991,7 +989,8 @@ static bool in_traverse(const struct op op[], unsigned int i)
static bool starts_chainlock(const struct op *op) static bool starts_chainlock(const struct op *op)
{ {
return op->op == OP_TDB_CHAINLOCK_READ || op->op == OP_TDB_CHAINLOCK; return op->type == OP_TDB_CHAINLOCK_READ
|| op->type == OP_TDB_CHAINLOCK;
} }
static bool in_chainlock(const struct op op[], unsigned int i) static bool in_chainlock(const struct op op[], unsigned int i)
...@@ -1007,11 +1006,11 @@ static const TDB_DATA *gives(const TDB_DATA *key, const TDB_DATA *pre, ...@@ -1007,11 +1006,11 @@ static const TDB_DATA *gives(const TDB_DATA *key, const TDB_DATA *pre,
unsigned int i; unsigned int i;
/* Cancelled transactions don't change anything. */ /* Cancelled transactions don't change anything. */
if (op[op->group_len].op == OP_TDB_TRANSACTION_CANCEL) if (op[op->group_len].type == OP_TDB_TRANSACTION_CANCEL)
return pre; return pre;
assert(op[op->group_len].op == OP_TDB_TRANSACTION_COMMIT assert(op[op->group_len].type == OP_TDB_TRANSACTION_COMMIT
|| op[op->group_len].op == OP_TDB_CHAINUNLOCK_READ || op[op->group_len].type == OP_TDB_CHAINUNLOCK_READ
|| op[op->group_len].op == OP_TDB_CHAINUNLOCK); || op[op->group_len].type == OP_TDB_CHAINUNLOCK);
for (i = 1; i < op->group_len; i++) { for (i = 1; i < op->group_len; i++) {
/* This skips nested transactions, too */ /* This skips nested transactions, too */
...@@ -1025,13 +1024,13 @@ static const TDB_DATA *gives(const TDB_DATA *key, const TDB_DATA *pre, ...@@ -1025,13 +1024,13 @@ static const TDB_DATA *gives(const TDB_DATA *key, const TDB_DATA *pre,
if (op->ret < 0) if (op->ret < 0)
return pre; return pre;
if (op->op == OP_TDB_DELETE || op->op == OP_TDB_WIPE_ALL) if (op->type == OP_TDB_DELETE || op->type == OP_TDB_WIPE_ALL)
return &tdb_null; return &tdb_null;
if (op->op == OP_TDB_APPEND) if (op->type == OP_TDB_APPEND)
return &op->append.post; return &op->append.post;
if (op->op == OP_TDB_STORE) if (op->type == OP_TDB_STORE)
return &op->data; return &op->data;
return pre; return pre;
...@@ -1067,7 +1066,7 @@ static struct keyinfo *hash_ops(struct op *op[], unsigned int num_ops[], ...@@ -1067,7 +1066,7 @@ static struct keyinfo *hash_ops(struct op *op[], unsigned int num_ops[],
op[i][j].key.dptr = hash[h].key.dptr; op[i][j].key.dptr = hash[h].key.dptr;
} }
hash[h].user = talloc_realloc(hash, hash[h].user, hash[h].user = talloc_realloc(hash, hash[h].user,
struct key_user, struct op_desc,
hash[h].num_users+1); hash[h].num_users+1);
/* If it's in a transaction, it's the transaction which /* If it's in a transaction, it's the transaction which
...@@ -1114,7 +1113,7 @@ static bool satisfies(const TDB_DATA *key, const TDB_DATA *data, ...@@ -1114,7 +1113,7 @@ static bool satisfies(const TDB_DATA *key, const TDB_DATA *data,
* specific requirements (eg. store or delete), * specific requirements (eg. store or delete),
* but they change the value so we can't get * but they change the value so we can't get
* more information from future ops. */ * more information from future ops. */
if (op[i].op != OP_TDB_EXISTS) if (op[i].type != OP_TDB_EXISTS)
break; break;
} }
} }
...@@ -1146,26 +1145,26 @@ static bool satisfies(const TDB_DATA *key, const TDB_DATA *data, ...@@ -1146,26 +1145,26 @@ static bool satisfies(const TDB_DATA *key, const TDB_DATA *data,
return key_eq(*data, *need); return key_eq(*data, *need);
} }
static void move_to_front(struct key_user res[], unsigned off, unsigned elem) static void move_to_front(struct op_desc res[], unsigned off, unsigned elem)
{ {
if (elem != off) { if (elem != off) {
struct key_user tmp = res[elem]; struct op_desc tmp = res[elem];
memmove(res + off + 1, res + off, (elem - off)*sizeof(res[0])); memmove(res + off + 1, res + off, (elem - off)*sizeof(res[0]));
res[off] = tmp; res[off] = tmp;
} }
} }
static void restore_to_pos(struct key_user res[], unsigned off, unsigned elem) static void restore_to_pos(struct op_desc res[], unsigned off, unsigned elem)
{ {
if (elem != off) { if (elem != off) {
struct key_user tmp = res[off]; struct op_desc tmp = res[off];
memmove(res + off, res + off + 1, (elem - off)*sizeof(res[0])); memmove(res + off, res + off + 1, (elem - off)*sizeof(res[0]));
res[elem] = tmp; res[elem] = tmp;
} }
} }
static bool sort_deps(char *filename[], struct op *op[], static bool sort_deps(char *filename[], struct op *op[],
struct key_user res[], struct op_desc res[],
unsigned off, unsigned num, unsigned off, unsigned num,
const TDB_DATA *key, const TDB_DATA *data, const TDB_DATA *key, const TDB_DATA *data,
unsigned num_files, unsigned fuzz) unsigned num_files, unsigned fuzz)
...@@ -1178,15 +1177,15 @@ static bool sort_deps(char *filename[], struct op *op[], ...@@ -1178,15 +1177,15 @@ static bool sort_deps(char *filename[], struct op *op[],
if (off == num) if (off == num)
return true; return true;
/* Does this make serial numbers go backwards? Allow a little fuzz. */ /* Does this make sequence number go backwards? Allow a little fuzz. */
if (off > 0) { if (off > 0) {
int serial1 = op[res[off-1].file][res[off-1].op_num].serial; int seqnum1 = op[res[off-1].file][res[off-1].op_num].seqnum;
int serial2 = op[res[off].file][res[off].op_num].serial; int seqnum2 = op[res[off].file][res[off].op_num].seqnum;
if (serial1 - serial2 > (int)fuzz) { if (seqnum1 - seqnum2 > (int)fuzz) {
#if DEBUG_DEPS #if DEBUG_DEPS
printf("Serial jump too far (%u -> %u)\n", printf("Seqnum jump too far (%u -> %u)\n",
serial1, serial2); seqnum1, seqnum2);
#endif #endif
return false; return false;
} }
...@@ -1197,7 +1196,7 @@ static bool sort_deps(char *filename[], struct op *op[], ...@@ -1197,7 +1196,7 @@ static bool sort_deps(char *filename[], struct op *op[],
/* Since ops within a trace file are ordered, we just need to figure /* Since ops within a trace file are ordered, we just need to figure
* out which file to try next. Since we don't take into account * out which file to try next. Since we don't take into account
* inter-key relationships (which exist by virtue of trace file order), * inter-key relationships (which exist by virtue of trace file order),
* we minimize the chance of harm by trying to keep in serial order. */ * we minimize the chance of harm by trying to keep in seqnum order. */
for (files_done = 0, i = off; i < num && files_done < num_files; i++) { for (files_done = 0, i = off; i < num && files_done < num_files; i++) {
if (done[res[i].file]) if (done[res[i].file])
continue; continue;
...@@ -1221,7 +1220,7 @@ static bool sort_deps(char *filename[], struct op *op[], ...@@ -1221,7 +1220,7 @@ static bool sort_deps(char *filename[], struct op *op[],
return false; return false;
} }
static void check_dep_sorting(struct key_user user[], unsigned num_users, static void check_dep_sorting(struct op_desc user[], unsigned num_users,
unsigned num_files) unsigned num_files)
{ {
#if DEBUG_DEPS #if DEBUG_DEPS
...@@ -1239,19 +1238,19 @@ static void check_dep_sorting(struct key_user user[], unsigned num_users, ...@@ -1239,19 +1238,19 @@ static void check_dep_sorting(struct key_user user[], unsigned num_users,
/* All these ops happen on the same key. Which comes first? /* All these ops happen on the same key. Which comes first?
* *
* This can happen both because read ops or failed write ops don't * This can happen both because read ops or failed write ops don't
* change serial number, and also due to race since we access the * change sequence number, and also due to race since we access the
* number unlocked (the race can cause less detectable ordering problems, * number unlocked (the race can cause less detectable ordering problems,
* in which case we'll deadlock and report: fix manually in that case). * in which case we'll deadlock and report: fix manually in that case).
*/ */
static void figure_deps(char *filename[], struct op *op[], static void figure_deps(char *filename[], struct op *op[],
const TDB_DATA *key, struct key_user user[], const TDB_DATA *key, struct op_desc user[],
unsigned num_users, unsigned num_files) unsigned num_users, unsigned num_files)
{ {
/* We assume database starts empty. */ /* We assume database starts empty. */
const struct TDB_DATA *data = &tdb_null; const struct TDB_DATA *data = &tdb_null;
unsigned int fuzz; unsigned int fuzz;
/* We prefer to keep strict serial order if possible: it's the /* We prefer to keep strict seqnum order if possible: it's the
* most likely. We get more lax if that fails. */ * most likely. We get more lax if that fails. */
for (fuzz = 0; fuzz < 100; fuzz = (fuzz + 1)*2) { for (fuzz = 0; fuzz < 100; fuzz = (fuzz + 1)*2) {
if (sort_deps(filename, op, user, 0, num_users, key, data, if (sort_deps(filename, op, user, 0, num_users, key, data,
...@@ -1272,19 +1271,19 @@ static void sort_ops(struct keyinfo hash[], char *filename[], struct op *op[], ...@@ -1272,19 +1271,19 @@ static void sort_ops(struct keyinfo hash[], char *filename[], struct op *op[],
unsigned int h; unsigned int h;
/* Gcc nexted function extension. How cool is this? */ /* Gcc nexted function extension. How cool is this? */
int compare_serial(const void *_a, const void *_b) int compare_seqnum(const void *_a, const void *_b)
{ {
const struct key_user *a = _a, *b = _b; const struct op_desc *a = _a, *b = _b;
/* First, maintain order within any trace file. */ /* First, maintain order within any trace file. */
if (a->file == b->file) if (a->file == b->file)
return a->op_num - b->op_num; return a->op_num - b->op_num;
/* Otherwise, arrange by serial order. */ /* Otherwise, arrange by seqnum order. */
if (op[a->file][a->op_num].serial != if (op[a->file][a->op_num].seqnum !=
op[b->file][b->op_num].serial) op[b->file][b->op_num].seqnum)
return op[a->file][a->op_num].serial return op[a->file][a->op_num].seqnum
- op[b->file][b->op_num].serial; - op[b->file][b->op_num].seqnum;
/* Cancelled transactions are assumed to happen first. */ /* Cancelled transactions are assumed to happen first. */
if (starts_transaction(&op[a->file][a->op_num]) if (starts_transaction(&op[a->file][a->op_num])
...@@ -1298,11 +1297,11 @@ static void sort_ops(struct keyinfo hash[], char *filename[], struct op *op[], ...@@ -1298,11 +1297,11 @@ static void sort_ops(struct keyinfo hash[], char *filename[], struct op *op[],
return 0; return 0;
} }
/* Now sort into serial order. */ /* Now sort into seqnum order. */
for (h = 0; h < total_keys * 2; h++) { for (h = 0; h < total_keys * 2; h++) {
struct key_user *user = hash[h].user; struct op_desc *user = hash[h].user;
qsort(user, hash[h].num_users, sizeof(user[0]), compare_serial); qsort(user, hash[h].num_users, sizeof(user[0]), compare_seqnum);
figure_deps(filename, op, &hash[h].key, user, hash[h].num_users, figure_deps(filename, op, &hash[h].key, user, hash[h].num_users,
num); num);
} }
...@@ -1318,42 +1317,44 @@ static int destroy_depend(struct depend *dep) ...@@ -1318,42 +1317,44 @@ static int destroy_depend(struct depend *dep)
static void add_dependency(void *ctx, static void add_dependency(void *ctx,
struct op *op[], struct op *op[],
char *filename[], char *filename[],
unsigned int needs_file, const struct op_desc *needs,
unsigned int needs_opnum, const struct op_desc *prereq)
unsigned int satisfies_file,
unsigned int satisfies_opnum)
{ {
struct depend *dep; struct depend *dep;
/* We don't depend on ourselves. */ /* We don't depend on ourselves. */
if (needs_file == satisfies_file) { if (needs->file == prereq->file) {
assert(satisfies_opnum < needs_opnum); assert(prereq->op_num < needs->op_num);
return; return;
} }
#if DEBUG_DEPS #if DEBUG_DEPS
printf("%s:%u: depends on %s:%u\n", printf("%s:%u: depends on %s:%u\n",
filename[needs_file], needs_opnum+1, filename[needs->file], needs->op_num+1,
filename[satisfies_file], satisfies_opnum+1); filename[prereq->file], prereq->op_num+1);
#endif #endif
dep = talloc(ctx, struct depend);
dep->needs = *needs;
dep->prereq = *prereq;
#if TRAVERSALS_TAKE_TRANSACTION_LOCK #if TRAVERSALS_TAKE_TRANSACTION_LOCK
/* If something in a traverse depends on something in another /* If something in a traverse depends on something in another
* traverse/transaction, it creates a dependency between the * traverse/transaction, it creates a dependency between the
* two groups. */ * two groups. */
if ((in_traverse(op[satisfies_file], satisfies_opnum) if ((in_traverse(op[prereq->file], prereq->op_num)
&& (starts_transaction(&op[needs_file][needs_opnum]) && (starts_transaction(&op[needs->file][needs->op_num])
|| starts_traverse(&op[needs_file][needs_opnum]))) || starts_traverse(&op[needs->file][needs->op_num])))
|| (in_traverse(op[needs_file], needs_opnum) || (in_traverse(op[needs->file], needs->op_num)
&& (starts_transaction(&op[satisfies_file][satisfies_opnum]) && (starts_transaction(&op[prereq->file][prereq->op_num])
|| starts_traverse(&op[satisfies_file][satisfies_opnum])))){ || starts_traverse(&op[prereq->file][prereq->op_num])))) {
unsigned int sat; unsigned int start;
/* We are satisfied by end of group. */ /* We are satisfied by end of group. */
sat = op[satisfies_file][satisfies_opnum].group_start; start = op[prereq->file][prereq->op_num].group_start;
satisfies_opnum = sat + op[satisfies_file][sat].group_len; dep->prereq.op_num = start + op[prereq->file][start].group_len;
/* And we need that done by start of our group. */ /* And we need that done by start of our group. */
needs_opnum = op[needs_file][needs_opnum].group_start; dep->needs.op_num = op[needs->file][needs->op_num].group_start;
} }
/* There is also this case: /* There is also this case:
...@@ -1365,44 +1366,38 @@ static void add_dependency(void *ctx, ...@@ -1365,44 +1366,38 @@ static void add_dependency(void *ctx,
* We try to address this by ensuring that where seqnum indicates it's * We try to address this by ensuring that where seqnum indicates it's
* possible, we wait for <create foo> before *starting* traverse. * possible, we wait for <create foo> before *starting* traverse.
*/ */
else if (in_traverse(op[needs_file], needs_opnum)) { else if (in_traverse(op[needs->file], needs->op_num)) {
struct op *need = &op[needs_file][needs_opnum]; struct op *need = &op[needs->file][needs->op_num];
if (op[needs_file][need->group_start].serial > if (op[needs->file][need->group_start].seqnum >
op[satisfies_file][satisfies_opnum].serial) { op[prereq->file][prereq->op_num].seqnum) {
needs_opnum = need->group_start; dep->needs.op_num = need->group_start;
} }
} }
#endif #endif
/* If you depend on a transaction or chainlock, you actually /* If you depend on a transaction or chainlock, you actually
* depend on it ending. */ * depend on it ending. */
if (starts_transaction(&op[satisfies_file][satisfies_opnum]) if (starts_transaction(&op[prereq->file][dep->prereq.op_num])
|| starts_chainlock(&op[satisfies_file][satisfies_opnum])) { || starts_chainlock(&op[prereq->file][dep->prereq.op_num])) {
satisfies_opnum dep->prereq.op_num
+= op[satisfies_file][satisfies_opnum].group_len; += op[dep->prereq.file][dep->prereq.op_num].group_len;
#if DEBUG_DEPS #if DEBUG_DEPS
printf("-> Actually end of transaction %s:%u\n", printf("-> Actually end of transaction %s:%u\n",
filename[satisfies_file], satisfies_opnum+1); filename[dep->prereq->file], dep->prereq->op_num+1);
#endif #endif
} else } else
/* We should never create a dependency from middle of /* We should never create a dependency from middle of
* a transaction. */ * a transaction. */
assert(!in_transaction(op[satisfies_file], satisfies_opnum) assert(!in_transaction(op[prereq->file], dep->prereq.op_num)
|| op[satisfies_file][satisfies_opnum].op || op[prereq->file][dep->prereq.op_num].type
== OP_TDB_TRANSACTION_COMMIT == OP_TDB_TRANSACTION_COMMIT
|| op[satisfies_file][satisfies_opnum].op || op[prereq->file][dep->prereq.op_num].type
== OP_TDB_TRANSACTION_CANCEL); == OP_TDB_TRANSACTION_CANCEL);
assert(op[needs_file][needs_opnum].op != OP_TDB_TRAVERSE); list_add(&op[dep->prereq.file][dep->prereq.op_num].post,
assert(op[satisfies_file][satisfies_opnum].op != OP_TDB_TRAVERSE); &dep->post_list);
list_add(&op[dep->needs.file][dep->needs.op_num].pre,
dep = talloc(ctx, struct depend); &dep->pre_list);
dep->needs_file = needs_file;
dep->needs_opnum = needs_opnum;
dep->satisfies_file = satisfies_file;
dep->satisfies_opnum = satisfies_opnum;
list_add(&op[satisfies_file][satisfies_opnum].post, &dep->post_list);
list_add(&op[needs_file][needs_opnum].pre, &dep->pre_list);
talloc_set_destructor(dep, destroy_depend); talloc_set_destructor(dep, destroy_depend);
} }
...@@ -1414,7 +1409,7 @@ static bool changes_db(const TDB_DATA *key, const struct op *op) ...@@ -1414,7 +1409,7 @@ static bool changes_db(const TDB_DATA *key, const struct op *op)
static void depend_on_previous(struct op *op[], static void depend_on_previous(struct op *op[],
char *filename[], char *filename[],
unsigned int num, unsigned int num,
struct key_user user[], struct op_desc user[],
unsigned int i, unsigned int i,
int prev) int prev)
{ {
...@@ -1426,9 +1421,7 @@ static void depend_on_previous(struct op *op[], ...@@ -1426,9 +1421,7 @@ static void depend_on_previous(struct op *op[],
if (prev == i - 1) { if (prev == i - 1) {
/* Just depend on previous. */ /* Just depend on previous. */
add_dependency(NULL, op, filename, add_dependency(NULL, op, filename, &user[i], &user[prev]);
user[i].file, user[i].op_num,
user[prev].file, user[prev].op_num);
return; return;
} }
...@@ -1437,9 +1430,7 @@ static void depend_on_previous(struct op *op[], ...@@ -1437,9 +1430,7 @@ static void depend_on_previous(struct op *op[],
deps[user[i].file] = true; deps[user[i].file] = true;
for (j = i - 1; j > prev; j--) { for (j = i - 1; j > prev; j--) {
if (!deps[user[j].file]) { if (!deps[user[j].file]) {
add_dependency(NULL, op, filename, add_dependency(NULL, op, filename, &user[i], &user[j]);
user[i].file, user[i].op_num,
user[j].file, user[j].op_num);
deps[user[j].file] = true; deps[user[j].file] = true;
} }
} }
...@@ -1461,14 +1452,14 @@ static void optimize_dependencies(struct op *op[], unsigned int num_ops[], ...@@ -1461,14 +1452,14 @@ static void optimize_dependencies(struct op *op[], unsigned int num_ops[],
memset(prev, 0, sizeof(prev)); memset(prev, 0, sizeof(prev));
list_for_each_safe(&op[i][j].pre, dep, next, pre_list) { list_for_each_safe(&op[i][j].pre, dep, next, pre_list) {
if (!prev[dep->satisfies_file]) { if (!prev[dep->prereq.file]) {
prev[dep->satisfies_file] = dep; prev[dep->prereq.file] = dep;
continue; continue;
} }
if (prev[dep->satisfies_file]->satisfies_opnum if (prev[dep->prereq.file]->prereq.op_num
< dep->satisfies_opnum) { < dep->prereq.op_num) {
talloc_free(prev[dep->satisfies_file]); talloc_free(prev[dep->prereq.file]);
prev[dep->satisfies_file] = dep; prev[dep->prereq.file] = dep;
} else } else
talloc_free(dep); talloc_free(dep);
} }
...@@ -1485,23 +1476,18 @@ static void optimize_dependencies(struct op *op[], unsigned int num_ops[], ...@@ -1485,23 +1476,18 @@ static void optimize_dependencies(struct op *op[], unsigned int num_ops[],
struct depend *dep, *next; struct depend *dep, *next;
list_for_each_safe(&op[i][j].pre, dep, next, pre_list) { list_for_each_safe(&op[i][j].pre, dep, next, pre_list) {
if (deps[dep->satisfies_file] if (deps[dep->prereq.file]
>= (int)dep->satisfies_opnum) >= (int)dep->prereq.op_num)
talloc_free(dep); talloc_free(dep);
else else
deps[dep->satisfies_file] deps[dep->prereq.file]
= dep->satisfies_opnum; = dep->prereq.op_num;
} }
} }
} }
} }
#if TRAVERSALS_TAKE_TRANSACTION_LOCK #if TRAVERSALS_TAKE_TRANSACTION_LOCK
struct traverse_dep {
unsigned int file;
unsigned int op_num;
};
/* Force an order among the traversals, so they don't deadlock (as much) */ /* Force an order among the traversals, so they don't deadlock (as much) */
static void make_traverse_depends(char *filename[], static void make_traverse_depends(char *filename[],
struct op *op[], unsigned int num_ops[], struct op *op[], unsigned int num_ops[],
...@@ -1509,24 +1495,24 @@ static void make_traverse_depends(char *filename[], ...@@ -1509,24 +1495,24 @@ static void make_traverse_depends(char *filename[],
{ {
unsigned int i, num_traversals = 0; unsigned int i, num_traversals = 0;
int j; int j;
struct traverse_dep *dep; struct op_desc *desc;
/* Sort by which one runs first. */ /* Sort by which one runs first. */
int compare_traverse_dep(const void *_a, const void *_b) int compare_traverse_desc(const void *_a, const void *_b)
{ {
const struct traverse_dep *ta = _a, *tb = _b; const struct op_desc *da = _a, *db = _b;
const struct op *a = &op[ta->file][ta->op_num], const struct op *a = &op[da->file][da->op_num],
*b = &op[tb->file][tb->op_num]; *b = &op[db->file][db->op_num];
if (a->serial != b->serial) if (a->seqnum != b->seqnum)
return a->serial - b->serial; return a->seqnum - b->seqnum;
/* If they have same serial, it means one didn't make any /* If they have same seqnum, it means one didn't make any
* changes. Thus sort by end in that case. */ * changes. Thus sort by end in that case. */
return a[a->group_len].serial - b[b->group_len].serial; return a[a->group_len].seqnum - b[b->group_len].seqnum;
} }
dep = talloc_array(NULL, struct traverse_dep, 1); desc = talloc_array(NULL, struct op_desc, 1);
/* Count them. */ /* Count them. */
for (i = 0; i < num; i++) { for (i = 0; i < num; i++) {
...@@ -1536,36 +1522,35 @@ static void make_traverse_depends(char *filename[], ...@@ -1536,36 +1522,35 @@ static void make_traverse_depends(char *filename[],
* transaction dependencies). */ * transaction dependencies). */
if (starts_traverse(&op[i][j]) if (starts_traverse(&op[i][j])
&& !in_transaction(op[i], j)) { && !in_transaction(op[i], j)) {
dep = talloc_realloc(NULL, dep, desc = talloc_realloc(NULL, desc,
struct traverse_dep, struct op_desc,
num_traversals+1); num_traversals+1);
dep[num_traversals].file = i; desc[num_traversals].file = i;
dep[num_traversals].op_num = j; desc[num_traversals].op_num = j;
num_traversals++; num_traversals++;
} }
} }
} }
qsort(dep, num_traversals, sizeof(dep[0]), compare_traverse_dep); qsort(desc, num_traversals, sizeof(desc[0]), compare_traverse_desc);
for (i = 1; i < num_traversals; i++) { for (i = 1; i < num_traversals; i++) {
const struct op *prev = &op[dep[i-1].file][dep[i-1].op_num]; const struct op *prev = &op[desc[i-1].file][desc[i-1].op_num];
const struct op *curr = &op[dep[i].file][dep[i].op_num]; const struct op *curr = &op[desc[i].file][desc[i].op_num];
/* Read traverses don't depend on each other (read lock). */ /* Read traverses don't depend on each other (read lock). */
if (prev->op == OP_TDB_TRAVERSE_READ_START if (prev->type == OP_TDB_TRAVERSE_READ_START
&& curr->op == OP_TDB_TRAVERSE_READ_START) && curr->type == OP_TDB_TRAVERSE_READ_START)
continue; continue;
/* Only make dependency if it's clear. */ /* Only make dependency if it's clear. */
if (compare_traverse_dep(&dep[i], &dep[i-1])) { if (compare_traverse_desc(&desc[i], &desc[i-1])) {
/* i depends on end of traverse i-1. */ /* i depends on end of traverse i-1. */
add_dependency(NULL, op, filename, struct op_desc end = desc[i-1];
dep[i].file, dep[i].op_num, end.op_num += prev->group_len;
dep[i-1].file, dep[i-1].op_num add_dependency(NULL, op, filename, &desc[i], &end);
+ prev->group_len);
} }
} }
talloc_free(dep); talloc_free(desc);
} }
#endif #endif
...@@ -1579,7 +1564,7 @@ static void derive_dependencies(char *filename[], ...@@ -1579,7 +1564,7 @@ static void derive_dependencies(char *filename[],
/* Create hash table for faster key lookup. */ /* Create hash table for faster key lookup. */
hash = hash_ops(op, num_ops, num); hash = hash_ops(op, num_ops, num);
/* Sort them by serial number. */ /* Sort them by sequence number. */
sort_ops(hash, filename, op, num); sort_ops(hash, filename, op, num);
/* Create dependencies back to the last change, rather than /* Create dependencies back to the last change, rather than
...@@ -1604,10 +1589,8 @@ static void derive_dependencies(char *filename[], ...@@ -1604,10 +1589,8 @@ static void derive_dependencies(char *filename[],
prev = i; prev = i;
} else if (prev >= 0) } else if (prev >= 0)
add_dependency(hash, op, filename, add_dependency(hash, op, filename,
hash[h].user[i].file, &hash[h].user[i],
hash[h].user[i].op_num, &hash[h].user[prev]);
hash[h].user[prev].file,
hash[h].user[prev].op_num);
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment