- /* Now handle the hard cases: same serial number. */
- sort_ops(hash, filename, op);
-
- /* We make the naive assumption that two ops on the same key
- * have to be ordered; it's overkill. */
- for (i = 0; i < total_keys * 2; i++) {
- for (j = 1; j < hash[i].num_users; j++) {
- add_dependency(hash, op, filename,
- hash[i].user[j].file,
- hash[i].user[j].op_num,
- hash[i].user[j-1].file,
- hash[i].user[j-1].op_num);
+ /* Sort them by serial number. */
+ sort_ops(hash, filename, op, num);
+
+ /* Create dependencies back to the last change, rather than
+ * creating false dependencies by naively making each one
+ * depend on the previous. This has two purposes: it makes
+ * later optimization simpler, and it also avoids deadlock with
+ * same sequence number ops inside traversals (if one
+ * traversal doesn't write anything, two ops can have the same
+ * sequence number yet we can create a traversal dependency
+ * the other way). */
+ for (h = 0; h < total_keys * 2; h++) {
+ int prev = -1;
+
+ if (hash[h].num_users < 2)
+ continue;
+
+ for (i = 0; i < hash[h].num_users; i++) {
+ if (changes_db(&hash[h].key, &op[hash[h].user[i].file]
+ [hash[h].user[i].op_num])) {
+ depend_on_previous(op, filename, num,
+ hash[h].user, i, prev);
+ prev = i;
+ } else if (prev >= 0)
+ add_dependency(hash, op, filename,
+ hash[h].user[i].file,
+ hash[h].user[i].op_num,
+ hash[h].user[prev].file,
+ hash[h].user[prev].op_num);