# # patch "database.cc" # from [a2c4dd49452b29eee2a1385541e55129060831be] # to [f5d7b0365d1cf8c64542ce5e072b0b82942442e8] # # patch "revision.cc" # from [abdb91c365c3e27be20f50508df16457056f3a61] # to [df925b5cb45b76df6a85d2b7da0a100121958331] # # patch "roster4.cc" # from [49a3aad6c40cbee029d6602f295aa9141e9219c0] # to [7f611745c3909e997d1d1a2df261ed09170f1111] # # patch "roster4.hh" # from [8e362ef36b54ab8eae6550a5bd47e2da5e0efba7] # to [99cc4c7912600a93876d270ac8af516b24f1c818] # # patch "transforms.cc" # from [ec5692a9ca5515b806c1e3b8c5ab3fe303f1f140] # to [a575f032108baee7827d56805ebc05f8fb4005ce] # # patch "transforms.hh" # from [ad5b4e603818a127c3b5a1c3eb365fe32d90da00] # to [a8097a706f9b6f087fb20213bd0002cae79fe844] # ======================================================================== --- database.cc a2c4dd49452b29eee2a1385541e55129060831be +++ database.cc f5d7b0365d1cf8c64542ce5e072b0b82942442e8 @@ -1369,14 +1369,27 @@ transaction_guard guard(*this); // Phase 2: construct a new roster and sanity-check its manifest_id - // against the manifest_id of the revision you're writing + // against the manifest_id of the revision you're writing. Also, to be + // *totally* thorough, check the manifest_ids of the parents of the new + // rev you're making and make sure they match the calculated manifest_id + // of their associated rosters. roster_t ros; marking_map mm; { manifest_id roster_manifest_id; make_roster_for_revision(rev, new_id, ros, mm, *__app); - calculate_ident(ros, mm, roster_manifest_id); + calculate_ident(ros, roster_manifest_id); I(rev.new_manifest == roster_manifest_id); + for (edge_map::const_iterator i = rev.edges.begin(); + i != rev.edges.end(); ++i) + { + roster_t parent_roster; + marking_map ignored; + manifest_id parent_mid; + get_roster(edge_old_revision(i), parent_roster, ignored); + calculate_ident(parent_roster, parent_mid); + I(edge_old_manifest(i) == parent_mid); + } } // Phase 3: Write the revision data ======================================================================== --- revision.cc abdb91c365c3e27be20f50508df16457056f3a61 +++ revision.cc df925b5cb45b76df6a85d2b7da0a100121958331 @@ -1081,7 +1081,7 @@ // Stuff related to rebuilding the revision graph. Unfortunately this is a // real enough error case that we need support code for it. - +/* static void analyze_manifest_changes(app_state & app, manifest_id const & parent, @@ -1130,8 +1130,8 @@ manifest_entry_id(i)); } } +*/ - struct anc_graph { anc_graph(bool existing, app_state & a) : @@ -1171,7 +1171,7 @@ void get_node_manifest(u64 node, manifest_id & man); u64 add_node_for_old_manifest(manifest_id const & man); u64 add_node_for_old_revision(revision_id const & rev); - revision_id construct_revision_from_ancestry(u64 child); + void construct_revisions_from_ancestry(); }; @@ -1434,32 +1434,83 @@ file_id const & fid, parent_roster_map const & parent_rosters, temp_node_id_source & nis, - roster_t const & child_roster) + roster_t & child_roster) { - node_id nid = create_file_node(i->second, nis); - split_path sp; - i->first.split(sp); + + split_path sp, dirname; + path_component basename; + pth.split(sp); + + E(!child_roster.has_node(sp), + F("Path %s added to child roster multiple times\n") % pth); + + dirname_basename(sp, dirname, basename); + + E(!dirname.empty(), + F("Empty path encountered during reconstruction\n")); + + // First, we make sure the entire dir containing the file in question has + // been inserted into the child roster. + { + split_path tmp_pth; + for (split_path::const_iterator i = dirname.begin(); i != dirname.end(); + ++i) + { + tmp_pth.push_back(*i); + if (child_roster.has_node(tmp_pth)) + { + E(is_dir_t(child_roster.get_node(tmp_pth)), + F("Directory for path %s cannot be added, as there is a file in the way\n") % pth); + } + else + child_roster.attach_node(child_roster.create_dir_node(nis), tmp_pth); + } + } + + // Then add a node for the file and attach it + node_id nid = child_roster.create_file_node(fid, nis); + child_roster.attach_node(nid, sp); + + // Finally, try to find a file in one of the parents which has the same name; + // if such a file is found, replace all the temporary node IDs we've assigned + // with the node IDs found in the parent. + for (parent_roster_map::const_iterator j = parent_rosters.begin(); j != parent_rosters.end(); ++j) { // We use a stupid heuristic: first parent who has // a file with the same name gets the node - // identity copied forward. Anything else is - // considered a new file. - boost::shared_ptr ros = j->second.first; - if (ros->has_node(sp)) + // identity copied forward. + boost::shared_ptr parent_roster = j->second.first; + if (parent_roster->has_node(sp)) { - node_t existing_node = ros->get_node(sp); - if (is_file_t(existing_node)) + node_t other_node = parent_roster->get_node(sp); + if (is_file_t(other_node)) { - child_roster.replace_node_id(nid, existing_node->self); - nid = existing_node->self; + // Here we've found an existing node for our file in a parent + // roster; For example, we have foo1=p/foo2=q/foo3=r in our + // child roster, and we've found foo1=x/foo2=y/foo3=z in a + // parent roster. We want to perform the following + // operations: + // + // child_roster.replace_node_id(r,z) + // child_roster.replace_node_id(q,y) + // child_roster.replace_node_id(p,x) + // + // where "foo1" is actually "", the root dir. + + for (node_id other_id = other_node->self; + ! null_node(other_id); + other_id = parent_roster->get_node(other_id)->parent) + { + child_roster.replace_node_id(nid, other_id); + nid = child_roster.get_node(nid)->parent; + } + I(null_node(nid)); break; } } } - child_roster.attach_node(); - //... } void @@ -1474,11 +1525,14 @@ // need to worry about one side of the frontier advancing faster than // another. + typedef std::multimap::const_iterator ci; std::multimap parent_to_child_map; std::deque work; std::set done; { + // Set up the parent->child mapping and prime the work queue + std::set parents, children; for (std::multimap::const_iterator i = ancestry.begin(); i != ancestry.end(); ++i) @@ -1498,9 +1552,8 @@ u64 child = work.front(); work.pop_front(); - typedef std::multimap::const_iterator ci; std::pair parent_range = ancestry.equal_range(child); - set parents; + std::set parents; bool parents_all_done = true; for (ci i = parent_range.first; parents_all_done && i != parent_range.second; ++i) { @@ -1520,11 +1573,11 @@ && (node_to_new_rev.find(child) == node_to_new_rev.end())) { L(F("processing node %d\n") % child); - revision_set rev; manifest_id old_child_mid; - get_node_manifest(child, old_child_mid); manifest_map old_child_man; + + get_node_manifest(child, old_child_mid); app.db.get_manifest(old_child_mid, old_child_man); // Load all the parent rosters into a temporary roster map @@ -1540,27 +1593,69 @@ boost::shared_ptr ros = boost::shared_ptr(new roster_t()); boost::shared_ptr mm = boost::shared_ptr(new marking_map()); app.db.get_roster(safe_get(node_to_new_rev, parent), *ros, *mm); - safe_insert(parent_rosters, std::make_pair(ros, mm)); + safe_insert(parent_rosters, std::make_pair(parent, std::make_pair(ros, mm))); } } - // Now convert the old-skool manifest into a cset adding all - // the files in question, and build a roster out of that. + // Convert the old-skool manifest into a cset adding all the + // files in question, and build a roster out of that. roster_t child_roster; temp_node_id_source nis; - { - for (manifest_map::const_iterator i = old_child_man.begin(); - i != old_child_man.end(); ++i) - { - insert_into_roster_reusing_parent_entries(i->first, i->second, - parent_rosters, - nis, child_roster); - } - } + for (manifest_map::const_iterator i = old_child_man.begin(); + i != old_child_man.end(); ++i) + { + insert_into_roster_reusing_parent_entries(i->first, i->second, + parent_rosters, + nis, child_roster); + } + + revision_set rev; + calculate_ident(child_roster, rev.new_manifest); + + // For each parent, construct an edge in the revision structure by analyzing the + // relationship between the parent roster and the child roster (and placing the + // result in a cset) + + for (parent_roster_map::const_iterator i = parent_rosters.begin(); + i != parent_rosters.end(); ++i) + { + u64 parent = i->first; + revision_id parent_rid = safe_get(node_to_new_rev, parent); + boost::shared_ptr parent_roster = i->second.first; + boost::shared_ptr cs = boost::shared_ptr(new cset()); + make_cset(*parent_roster, child_roster, *cs); + manifest_id parent_manifest_id; + calculate_ident(*parent_roster, parent_manifest_id); + safe_insert (rev.edges, std::make_pair (parent_rid, + std::make_pair (parent_manifest_id, cs))); + + } + + // Finally, put all this excitement into the database and save + // the new_rid for use in the cert-writing pass. + + revision_id new_rid; + calculate_ident(rev, new_rid); + node_to_new_rev.insert(std::make_pair(child, new_rid)); + + if (!app.db.revision_exists (new_rid)) + { + L(F("mapped node %d to revision %s\n") % child % new_rid); + app.db.put_revision(new_rid, rev); + ++n_revs_out; + } + else + { + L(F("skipping already existing revision %s\n") % new_rid); + } + + // Mark this child as done, hooray! + safe_insert(done, child); } } } +/* revision_id anc_graph::construct_revision_from_ancestry(u64 child) { @@ -1709,6 +1804,7 @@ return rid; } +*/ void build_changesets_from_existing_revs(app_state & app) @@ -1779,7 +1875,6 @@ graph.rebuild_ancestry(); } -*/ // i/o stuff ======================================================================== --- roster4.cc 49a3aad6c40cbee029d6602f295aa9141e9219c0 +++ roster4.cc 7f611745c3909e997d1d1a2df261ed09170f1111 @@ -76,13 +76,7 @@ // - const node_id the_null_node = 0; const node_id first_node = 1; - inline bool null_node(node_id n) - { - return n == the_null_node; - } - const node_id first_temp_node = widen(1) << (sizeof(node_id) * 8 - 1); inline bool temp_node(node_id n) { @@ -245,7 +239,7 @@ return *this; } -static inline void +void dirname_basename(split_path const & sp, split_path & dirname, path_component & basename) { @@ -790,6 +784,19 @@ } +temp_node_id_source::temp_node_id_source() + : curr(first_temp_node) +{} + +node_id +temp_node_id_source::next() +{ + node_id n = curr++; + I(temp_node(n)); + return n; +} + + namespace { @@ -856,7 +863,6 @@ node_id_source & nis; }; - struct testing_node_id_source : public node_id_source { ======================================================================== --- roster4.hh 8e362ef36b54ab8eae6550a5bd47e2da5e0efba7 +++ roster4.hh 99cc4c7912600a93876d270ac8af516b24f1c818 @@ -32,6 +32,20 @@ typedef boost::shared_ptr file_t; typedef boost::shared_ptr dir_t; +// FIXME: perhaps move this to paths.{cc,hh} +void +dirname_basename(split_path const & sp, + split_path & dirname, path_component & basename); + +node_id const the_null_node = 0; + +inline bool +null_node(node_id n) +{ + return n == the_null_node; +} + + // (true, "val") or (false, "") are both valid attr values (for proper // merging, we have to widen the attr_value type to include a first-class // "undefined" value). @@ -207,13 +221,8 @@ struct temp_node_id_source : public node_id_source { - temp_node_id_source() : curr(first_temp_node) {} - virtual node_id next() - { - node_id n = curr++; - I(temp_node(n)); - return n; - } + temp_node_id_source(); + virtual node_id next(); node_id curr; }; ======================================================================== --- transforms.cc ec5692a9ca5515b806c1e3b8c5ab3fe303f1f140 +++ transforms.cc a575f032108baee7827d56805ebc05f8fb4005ce @@ -326,11 +326,11 @@ // not include the local sequence numbers or markings, but produces // the manifest_id which is stored in the public revision_set object. void calculate_ident(roster_t const & ros, - marking_map const & mm, manifest_id & ident) { data tmp; hexenc tid; + marking_map mm; write_roster_and_marking(ros, mm, tmp, false); calculate_ident(tmp, tid); ident = tid; ======================================================================== --- transforms.hh ad5b4e603818a127c3b5a1c3eb365fe32d90da00 +++ transforms.hh a8097a706f9b6f087fb20213bd0002cae79fe844 @@ -140,7 +140,6 @@ // not include the local sequence numbers or markings, but produces // the manifest_id which is stored in the public revision_set object. void calculate_ident(roster_t const & ros, - marking_map const & mm, manifest_id & ident);