Browse Source

reconcile .../new and .../cur in a more intelligent way

David Mazieres 7 years ago
parent
commit
d322af0cab
2 changed files with 58 additions and 17 deletions
  1. 7
    0
      design.txt
  2. 51
    17
      protocol.cc

+ 7
- 0
design.txt View File

@@ -45,3 +45,10 @@ Keeping local database up to date:
45 45
     dir_docid, filename, docid
46 46
     tag, docid
47 47
 
48
+* Resolving a link conflict
49
+    Let n_A be the number of links of a file in xxx/new on replica A
50
+    Let c_A be the number of links in xxx/cur on replica A
51
+    Let n_B and c_B be the same for replica B
52
+    Put n links in xxx/new and c links in xxx/cur where
53
+      - c = max(c_A, c_B)
54
+      - n = max(n_A + c_A, n_B + c_B) - c

+ 51
- 17
protocol.cc View File

@@ -96,7 +96,6 @@ class msg_sync {
96 96
 
97 97
   static constexpr i64 bad_dir_id = -1;
98 98
   notmuch_database_t *notmuch();
99
-  void clear_committing();
100 99
   i64 get_dir_id (const string &dir, bool create);
101 100
 public:
102 101
   hash_lookup hashdb;
@@ -499,12 +498,6 @@ msg_sync::notmuch ()
499 498
   return notmuch_;
500 499
 }
501 500
 
502
-void
503
-msg_sync::clear_committing()
504
-{
505
-  sqlexec(db_, "DELETE FROM committing_fsops; DELETE FROM committing_tags; ");
506
-}
507
-
508 501
 static bool
509 502
 sanity_check_path (const string &path)
510 503
 {
@@ -584,6 +577,49 @@ notmuch_message_get_doc_id (const notmuch_message_t *message)
584 577
   return reinterpret_cast<const fake_message *>(message)->doc_id;
585 578
 }
586 579
 
580
+static void
581
+resolve_one_link_conflict(const unordered_map<string,i64> &a,
582
+			  const unordered_map<string,i64> &b,
583
+			  const string &name,
584
+			  unordered_map<string,i64> &out)
585
+{
586
+  if (out.find(name) != out.end())
587
+    return;
588
+  if (!dir_contains_messages(name)) {
589
+    out[name] = max(find_default(0, a, name), find_default(0, b, name));
590
+    return;
591
+  }
592
+
593
+  size_t pos = name.rfind('/');
594
+  if (pos == string::npos)
595
+    pos = 0;
596
+  else
597
+    pos++;
598
+  string base = name.substr(0, pos);
599
+  string newpath = base + "new", curpath = base + "cur";
600
+  cout << base << ' ' << newpath << ' ' << curpath << '\n';
601
+  i64 curval = max(find_default(0, a, curpath), find_default(0, b, curpath));
602
+  i64 newval = (max(find_default(0, a, curpath) + find_default(0, a, newpath),
603
+		    find_default(0, b, curpath) + find_default(0, b, newpath))
604
+		- curval);
605
+  if (curval)
606
+    out[curpath] = curval;
607
+  if (newval)
608
+    out[newpath] = newval;
609
+}
610
+
611
+static unordered_map<string,i64>
612
+resolve_link_conflicts(const unordered_map<string,i64> &a,
613
+		       const unordered_map<string,i64> &b)
614
+{
615
+  unordered_map<string,i64> ret;
616
+  for (auto ia : a)
617
+    resolve_one_link_conflict(a, b, ia.first, ret);
618
+  for (auto ib : b)
619
+    resolve_one_link_conflict(a, b, ib.first, ret);
620
+  return ret;
621
+}
622
+
587 623
 bool
588 624
 msg_sync::hash_sync(const versvector &rvv,
589 625
 		    const hash_info &rhi,
@@ -607,7 +643,9 @@ msg_sync::hash_sync(const versvector &rvv,
607 643
   bool links_conflict =
608 644
     lhi.hash_stamp.second > find_default (-1, rvv, lhi.hash_stamp.first);
609 645
   bool deleting = rhi.dirs.empty() && (!links_conflict || lhi.dirs.empty());
610
-  unordered_map<string,i64> needlinks (rhi.dirs);
646
+
647
+  unordered_map<string,i64> needlinks
648
+    (links_conflict ? resolve_link_conflicts (lhi.dirs, rhi.dirs) : rhi.dirs);
611 649
   bool needsource = false;
612 650
   for (auto i : lhi.dirs)
613 651
     needlinks[i.first] -= i.second;
@@ -628,8 +666,6 @@ msg_sync::hash_sync(const versvector &rvv,
628 666
       return false;
629 667
   }
630 668
 
631
-  sqlexec (db_, "SAVEPOINT hash_sync;");
632
-  cleanup c (sqlexec, db_, "ROLLBACK TO hash_sync;");
633 669
   if (!hashdb.ok()) {
634 670
     hashdb.create(rhi);
635 671
     lhi = hashdb.info();
@@ -638,7 +674,7 @@ msg_sync::hash_sync(const versvector &rvv,
638 674
   /* Adjust link counts in database */
639 675
   for (auto li : needlinks)
640 676
     if (li.second != 0) {
641
-      i64 dir_id = get_dir_id (li.first, li.second > 0);
677
+      i64 dir_id = get_dir_id(li.first, li.second > 0);
642 678
       if (dir_id == bad_dir_id)
643 679
 	continue;
644 680
       i64 newcount = find_default(0, lhi.dirs, li.first) + li.second;
@@ -698,7 +734,7 @@ msg_sync::hash_sync(const versvector &rvv,
698 734
 	   * already contains a hard link to the same inode, we need
699 735
 	   * to delete the original. */
700 736
 	  else
701
-	    err = unlink (path.c_str());
737
+	    unlink (path.c_str());
702 738
 	}
703 739
 	else {
704 740
 	  err = unlink (path.c_str());
@@ -708,11 +744,11 @@ msg_sync::hash_sync(const versvector &rvv,
708 744
 	}
709 745
 	if (!err) {
710 746
 	  ++n;
711
-	  notmuch_status_t err =
747
+	  notmuch_status_t status =
712 748
 	    notmuch_database_remove_message (notmuch(), path.c_str());
713
-	  if (err && err != NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID)
749
+	  if (status && status != NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID)
714 750
 	    throw runtime_error ("remove " + path + ": " +
715
-				 + notmuch_status_to_string(err));
751
+				 + notmuch_status_to_string(status));
716 752
 	}
717 753
       }
718 754
     }
@@ -720,8 +756,6 @@ msg_sync::hash_sync(const versvector &rvv,
720 756
   if (new_msgid && docid_valid)
721 757
     record_docid_.param(rhi.message_id, docid).step().reset();
722 758
 
723
-  c.disable();
724
-  sqlexec (db_, "RELEASE hash_sync;");
725 759
   if (clean_trash)
726 760
     unlink (trashname(hashdb.maildir, rhi.hash).c_str());
727 761
   return true;

Loading…
Cancel
Save