# # # patch "annotate.cc" # from [8bf75ac76a3eb4ed208196c5c24d440b1e3a7f3d] # to [797f71ea4777ab00858e20b283df08258375a3d0] # # patch "automate.cc" # from [b0e3a7c388ba135c5df0f383231f4a314799d4d8] # to [426f1065c0cadc6c511911ff200c4cd374436c77] # # patch "cmd_diff_log.cc" # from [fa9767c8d7388519dbccf9896ebf03749acf005a] # to [83d2bb41c536dbd438864353700ae3272c93f1e9] # # patch "cmd_merging.cc" # from [32e26ebbac982810c4c5fc5c9f00ba4cf3e9c260] # to [0863da85d59d73a4d604b155d6bcb360f557a1d1] # # patch "cow_trie.hh" # from [2033eefa4bbac0d39cc55b750a38cd39b13dfe79] # to [2751bc399b07e0facb652148d1af8d8fb77c9815] # # patch "database.cc" # from [2e1c65cb247666cfbf9d870f2a8be91153956625] # to [a018c1a6d772b1cf881950bb627b6a8d50258eda] # # patch "database.hh" # from [b78ece31bb4d90bc92abd7d29b46ef9651ae7975] # to [1e865016961f89451cce87636640221f4e2939cc] # # patch "database_check.cc" # from [d863d981b77df0e39aba1bd1213cb199d7c209ea] # to [939db552d558905604146370aac78f6b05a6ad6c] # # patch "merge_content.cc" # from [28f95337c83fa6740b5626aebcada3858f0a6900] # to [812920a264c04fa3d937910649cd4f488dca0ea2] # # patch "merge_roster.cc" # from [2319c20cf791d65ca7c52973e913ffaadf86be3a] # to [9c8e34b5521bde6f9a38f2996ce0edf51273e98d] # # patch "migrate_ancestry.cc" # from [0b324d2c3058e71712a06b1009fa199f04e1bc37] # to [d69ee0d4289d9d1f177dce56032c888a255faaf9] # # patch "rev_types.hh" # from [e7947946c6fef63393faeab7f47159c015c4e4c1] # to [84ec917e1fd84bd98d9c4b7ceb272bd6da84ac20] # # patch "roster.cc" # from [100158a2e40e8d0dce1050c991b48b60874e6b98] # to [f3998f2b6256d6af11d3ae19dc2b4520a6ffe189] # # patch "roster.hh" # from [d537c98290349bdd63a111cd0afafe39d3a9992d] # to [1b812efa037dd26dc72daa3e5ef41497a91a64bb] # # patch "roster_delta.cc" # from [5225677470dde8755581d7ae22081845ac428e60] # to [8d4fa4dc893653cd5f5a4575af1e96d7e03ef0b6] # # patch "roster_delta.hh" # from [8a78d49fa1d7b16ef457cf04367e97d052d1afcb] # to [e4eb1ea53028db1e8f75aefc9ccf41c2cb00afa6] # # patch "unit-tests/merge_roster.cc" # from [3a677e1cd5654fa5e41b1e1eee4708a8c2069fb0] # to [fd6d157c77b4f168bdc1ed29940beea69707e1a3] # # patch "unit-tests/roster.cc" # from [98207c6ccf55333e5407e3c32be85876426e34d6] # to [1d30d48443ab1cd3dc6ace38fbdca7aa3b3ef488] # ============================================================ --- annotate.cc 8bf75ac76a3eb4ed208196c5c24d440b1e3a7f3d +++ annotate.cc 797f71ea4777ab00858e20b283df08258375a3d0 @@ -688,14 +688,14 @@ static void get_file_content_marks(datab node_id const & fid, set & content_marks) { - marking_t markings; + const_marking_t markings; db.get_markings(rev, fid, markings); - I(!markings.file_content.empty()); + I(!markings->file_content.empty()); content_marks.clear(); - content_marks.insert(markings.file_content.begin(), - markings.file_content.end()); + content_marks.insert(markings->file_content.begin(), + markings->file_content.end()); } static void ============================================================ --- automate.cc b0e3a7c388ba135c5df0f383231f4a314799d4d8 +++ automate.cc 426f1065c0cadc6c511911ff200c4cd374436c77 @@ -990,10 +990,8 @@ inventory_determine_birth(inventory_item if (old_roster.has_node(item.new_node.id)) { const_node_t node = old_roster.get_node(item.new_node.id); - marking_map::const_iterator m = old_marking.find(node->self); - I(m != old_marking.end()); - marking_t mark = m->second; - rid = mark.birth_revision; + const_marking_t const & mark = old_marking.get_marking(node->self); + rid = mark->birth_revision; } return rid; } @@ -1894,13 +1892,11 @@ CMD_AUTOMATE(get_content_changed, N_("RE % path % ident); const_node_t node = new_roster.get_node(path); - marking_map::const_iterator m = mm.find(node->self); - I(m != mm.end()); - marking_t mark = m->second; + const_marking_t const & mark = mm.get_marking(node->self); basic_io::printer prt; - for (set::const_iterator i = mark.file_content.begin(); - i != mark.file_content.end(); ++i) + for (set::const_iterator i = mark->file_content.begin(); + i != mark->file_content.end(); ++i) { basic_io::stanza st; st.push_binary_pair(basic_io::syms::content_mark, i->inner()); ============================================================ --- cmd_diff_log.cc fa9767c8d7388519dbccf9896ebf03749acf005a +++ cmd_diff_log.cc 83d2bb41c536dbd438864353700ae3272c93f1e9 @@ -964,12 +964,12 @@ CMD(log, "log", "", CMD_REF(informative) if (mask.includes(roster, node)) { - marked_revs.insert(marks.file_content.begin(), - marks.file_content.end()); - marked_revs.insert(marks.parent_name.begin(), - marks.parent_name.end()); + marked_revs.insert(marks->file_content.begin(), + marks->file_content.end()); + marked_revs.insert(marks->parent_name.begin(), + marks->parent_name.end()); for (map >::const_iterator - a = marks.attrs.begin(); a != marks.attrs.end(); ++a) + a = marks->attrs.begin(); a != marks->attrs.end(); ++a) marked_revs.insert(a->second.begin(), a->second.end()); } } ============================================================ --- cmd_merging.cc 32e26ebbac982810c4c5fc5c9f00ba4cf3e9c260 +++ cmd_merging.cc 0863da85d59d73a4d604b155d6bcb360f557a1d1 @@ -676,11 +676,10 @@ CMD(merge_into_dir, "merge_into_dir", "" const_node_t parent = right_roster.get_node(dir); moved_root->parent = parent->self; moved_root->name = base; - marking_map::iterator - i = left_marking_map.find(moved_root->self); - I(i != left_marking_map.end()); - i->second.parent_name.clear(); - i->second.parent_name.insert(left_rid); + + marking_t i = left_marking_map.get_marking_for_update(moved_root->self); + i->parent_name.clear(); + i->parent_name.insert(left_rid); } roster_merge_result result; ============================================================ --- cow_trie.hh 2033eefa4bbac0d39cc55b750a38cd39b13dfe79 +++ cow_trie.hh 2751bc399b07e0facb652148d1af8d8fb77c9815 @@ -88,7 +88,7 @@ public: _count = 0; _data.reset(); } - void set(_Key key, _Value const & value) { + _Value const & set(_Key key, _Value const & value) { _Value *p; walk(_data, key, levels-1, &p); bool b = (*p != _empty_value); @@ -98,6 +98,7 @@ public: else if (a && !b) ++_count; *p = value; + return *p; } bool set_if_missing(_Key key, _Value const & value) { ============================================================ --- database.cc 2e1c65cb247666cfbf9d870f2a8be91153956625 +++ database.cc a018c1a6d772b1cf881950bb627b6a8d50258eda @@ -2042,10 +2042,10 @@ private: { private: node_id const & nid; - marking_t & markings; + const_marking_t & markings; public: - markings_extractor(node_id const & _nid, marking_t & _markings) : + markings_extractor(node_id const & _nid, const_marking_t & _markings) : nid(_nid), markings(_markings) {} ; bool look_at_delta(roster_delta const & del) @@ -2055,10 +2055,7 @@ public: void look_at_roster(roster_t const & roster, marking_map const & mm) { - marking_map::const_iterator mmi = - mm.find(nid); - I(mmi != mm.end()); - markings = mmi->second; + markings = mm.get_marking(nid); } }; @@ -2151,7 +2148,7 @@ database::get_markings(revision_id const void database::get_markings(revision_id const & id, node_id const & nid, - marking_t & markings) + const_marking_t & markings) { database_impl::markings_extractor x(nid, markings); imp->extract_from_deltas(id, x); ============================================================ --- database.hh b78ece31bb4d90bc92abd7d29b46ef9651ae7975 +++ database.hh 1e865016961f89451cce87636640221f4e2939cc @@ -219,7 +219,7 @@ public: // using roster deltas void get_markings(revision_id const & id, node_id const & nid, - marking_t & markings); + const_marking_t & markings); void get_file_content(revision_id const & id, node_id const & nid, ============================================================ --- database_check.cc d863d981b77df0e39aba1bd1213cb199d7c209ea +++ database_check.cc 939db552d558905604146370aac78f6b05a6ad6c @@ -264,21 +264,23 @@ check_rosters_marking(database & db, n != ros.all_nodes().end(); ++n) { // lots of revisions that must exist - marking_t mark = mm[n->first]; - checked_revisions[mark.birth_revision].marking_refs++; - if (!checked_revisions[mark.birth_revision].found) + if (!mm.contains(n->first)) + continue; + const_marking_t mark = mm.get_marking(n->first); + checked_revisions[mark->birth_revision].marking_refs++; + if (!checked_revisions[mark->birth_revision].found) checked_rosters[ros_id].missing_mark_revs++; - for (set::const_iterator r = mark.parent_name.begin(); - r != mark.parent_name.end(); r++) + for (set::const_iterator r = mark->parent_name.begin(); + r != mark->parent_name.end(); r++) { checked_revisions[*r].marking_refs++; if (!checked_revisions[*r].found) checked_rosters[ros_id].missing_mark_revs++; } - for (set::const_iterator r = mark.file_content.begin(); - r != mark.file_content.end(); r++) + for (set::const_iterator r = mark->file_content.begin(); + r != mark->file_content.end(); r++) { checked_revisions[*r].marking_refs++; if (!checked_revisions[*r].found) @@ -286,7 +288,7 @@ check_rosters_marking(database & db, } for (map >::const_iterator attr = - mark.attrs.begin(); attr != mark.attrs.end(); attr++) + mark->attrs.begin(); attr != mark->attrs.end(); attr++) for (set::const_iterator r = attr->second.begin(); r != attr->second.end(); r++) { ============================================================ --- merge_content.cc 28f95337c83fa6740b5626aebcada3858f0a6900 +++ merge_content.cc 812920a264c04fa3d937910649cd4f488dca0ea2 @@ -144,26 +144,20 @@ content_merge_database_adaptor::get_ance // then use the file's birth roster. if (!anc || !anc->has_node(nid)) { - marking_map::const_iterator lmm = left_mm.find(nid); - marking_map::const_iterator rmm = right_mm.find(nid); - - MM(left_mm); - MM(right_mm); - - if (lmm == left_mm.end()) + if (!left_mm.contains(nid)) { - I(rmm != right_mm.end()); - rid = rmm->second.birth_revision; + rid = right_mm.get_marking(nid)->birth_revision; } - else if (rmm == right_mm.end()) + else if (!right_mm.contains(nid)) { - I(lmm != left_mm.end()); - rid = lmm->second.birth_revision; + rid = left_mm.get_marking(nid)->birth_revision; } else { - I(lmm->second.birth_revision == rmm->second.birth_revision); - rid = lmm->second.birth_revision; + const_marking_t const & lm = left_mm.get_marking(nid); + const_marking_t const & rm = right_mm.get_marking(nid); + I(lm->birth_revision == rm->birth_revision); + rid = lm->birth_revision; } load_and_cache_roster(db, rid, rosters, anc); @@ -236,26 +230,20 @@ content_merge_workspace_adaptor::get_anc } else { - marking_map::const_iterator lmm = left_mm.find(nid); - marking_map::const_iterator rmm = right_mm.find(nid); - - MM(left_mm); - MM(right_mm); - - if (lmm == left_mm.end()) + if (!left_mm.contains(nid)) { - I(rmm != right_mm.end()); - rid = rmm->second.birth_revision; + rid = right_mm.get_marking(nid)->birth_revision; } - else if (rmm == right_mm.end()) + else if (!right_mm.contains(nid)) { - I(lmm != left_mm.end()); - rid = lmm->second.birth_revision; + rid = left_mm.get_marking(nid)->birth_revision; } else { - I(lmm->second.birth_revision == rmm->second.birth_revision); - rid = lmm->second.birth_revision; + const_marking_t const & lm = left_mm.get_marking(nid); + const_marking_t const & rm = right_mm.get_marking(nid); + I(lm->birth_revision == rm->birth_revision); + rid = lm->birth_revision; } load_and_cache_roster(db, rid, rosters, anc); ============================================================ --- merge_roster.cc 2319c20cf791d65ca7c52973e913ffaadf86be3a +++ merge_roster.cc 9c8e34b5521bde6f9a38f2996ce0edf51273e98d @@ -310,7 +310,8 @@ namespace roster_t const & parent_roster, roster_t & new_roster) { - revision_id const & birth = safe_get(markings, n->self).birth_revision; + const_marking_t const & m = markings.get_marking(n->self); + revision_id const & birth = m->birth_revision; if (uncommon_ancestors.find(birth) != uncommon_ancestors.end()) create_node_for(n, new_roster); else @@ -319,7 +320,7 @@ namespace // has been deleted from the other side of the merge. // In this case, output a warning if there are changes to the file on the // side of the merge where it still exists. - set const & content_marks = safe_get(markings, n->self).file_content; + set const & content_marks = m->file_content; bool found_one_ignored_content = false; for (set::const_iterator it = content_marks.begin(); it != content_marks.end(); it++) { @@ -587,10 +588,10 @@ roster_merge(roster_t const & left_paren left_name = make_pair(left_n->parent, left_n->name); right_name = make_pair(right_n->parent, right_n->name); if (merge_scalar(left_name, - left_marking.parent_name, + left_marking->parent_name, left_uncommon_ancestors, right_name, - right_marking.parent_name, + right_marking->parent_name, right_uncommon_ancestors, new_name, conflict)) { @@ -623,10 +624,10 @@ roster_merge(roster_t const & left_paren { file_content_conflict conflict(new_n->self); if (merge_scalar(downcast_to_file_t(left_n)->content, - left_marking.file_content, + left_marking->file_content, left_uncommon_ancestors, downcast_to_file_t(right_n)->content, - right_marking.file_content, + right_marking->file_content, right_uncommon_ancestors, downcast_to_file_t(new_n)->content, conflict)) @@ -663,11 +664,11 @@ roster_merge(roster_t const & left_paren conflict.key = attr_i.left_key(); I(conflict.key == attr_i.right_key()); if (merge_scalar(attr_i.left_data(), - safe_get(left_marking.attrs, + safe_get(left_marking->attrs, attr_i.left_key()), left_uncommon_ancestors, attr_i.right_data(), - safe_get(right_marking.attrs, + safe_get(right_marking->attrs, attr_i.right_key()), right_uncommon_ancestors, new_value, ============================================================ --- migrate_ancestry.cc 0b324d2c3058e71712a06b1009fa199f04e1bc37 +++ migrate_ancestry.cc d69ee0d4289d9d1f177dce56032c888a255faaf9 @@ -548,7 +548,7 @@ anc_graph::fixup_node_identities(parent_ for (node_map::const_iterator j = nodes.begin(); j != nodes.end(); ++j) { node_id n = j->first; - revision_id birth_rev = safe_get(*parent_marking, n).birth_revision; + revision_id birth_rev = parent_marking->get_marking(n)->birth_revision; u64 birth_node = safe_get(new_rev_to_node, birth_rev); map::const_iterator i = nodes_in_any_parent.find(n); if (i != nodes_in_any_parent.end()) ============================================================ --- rev_types.hh e7947946c6fef63393faeab7f47159c015c4e4c1 +++ rev_types.hh 84ec917e1fd84bd98d9c4b7ceb272bd6da84ac20 @@ -68,7 +68,7 @@ struct file_node; struct node; struct dir_node; struct file_node; -struct marking_t; +struct marking; class roster_t; class editable_roster_base; @@ -80,7 +80,9 @@ typedef boost::shared_ptr const_file_t; typedef boost::shared_ptr const_dir_t; -typedef std::map marking_map; +typedef boost::shared_ptr marking_t; +typedef boost::shared_ptr const_marking_t; +class marking_map; typedef std::map dir_map; //typedef hybrid_map node_map; ============================================================ --- roster.cc 100158a2e40e8d0dce1050c991b48b60874e6b98 +++ roster.cc f3998f2b6256d6af11d3ae19dc2b4520a6ffe189 @@ -98,14 +98,14 @@ dump(marking_t const & marking, string & { ostringstream oss; string tmp; - oss << "birth_revision: " << marking.birth_revision << '\n'; - dump(marking.parent_name, tmp); + oss << "birth_revision: " << marking->birth_revision << '\n'; + dump(marking->parent_name, tmp); oss << "parent_name: " << tmp << '\n'; - dump(marking.file_content, tmp); + dump(marking->file_content, tmp); oss << "file_content: " << tmp << '\n'; - oss << "attrs (number: " << marking.attrs.size() << "):\n"; + oss << "attrs (number: " << marking->attrs.size() << "):\n"; for (map >::const_iterator - i = marking.attrs.begin(); i != marking.attrs.end(); ++i) + i = marking->attrs.begin(); i != marking->attrs.end(); ++i) { dump(i->second, tmp); oss << " " << i->first << ": " << tmp << '\n'; @@ -158,6 +158,119 @@ u32 last_created_roster = 0; u32 last_created_roster = 0; + +marking::marking() + : cow_version(0) +{ } + +marking::marking(marking const & other) + : cow_version(0), + birth_revision(other.birth_revision), + parent_name(other.parent_name), + file_content(other.file_content), + attrs(other.attrs) +{ +} + +marking const & marking::operator=(marking const & other) +{ + cow_version = 0; + birth_revision = other.birth_revision; + parent_name = other.parent_name; + file_content = other.file_content; + attrs = other.attrs; + return *this; +} + +marking_map::marking_map() + : cow_version(++last_created_roster) +{ } + +marking_map::marking_map(marking_map const & other) + : cow_version(++last_created_roster), + _store(other._store) +{ + other.cow_version = ++last_created_roster; +} + +marking_map const & marking_map::operator=(marking_map const & other) +{ + cow_version = ++last_created_roster; + other.cow_version = ++last_created_roster; + _store = other._store; + return *this; +} + +void marking_map::clear() +{ + cow_version = ++last_created_roster; + _store.clear(); +} + +const_marking_t marking_map::get_marking(node_id nid) const +{ + marking_t const & m = _store.get_if_present(nid); + I(m); + return m; +} + +marking_t const & marking_map::get_marking_for_update(node_id nid) +{ + marking_t const & m = _store.get_unshared_if_present(nid); + I(m); + if (cow_version == m->cow_version) + return m; + if (m.unique()) + { + m->cow_version = cow_version; + return m; + } + return _store.set(nid, marking_t(new marking(*m))); +} + +bool marking_map::contains(node_id nid) const +{ + return _store.get_if_present(nid); +} + +void marking_map::remove_marking(node_id nid) +{ + unsigned pre_sz = _store.size(); + _store.unset(nid); + I(_store.size() == pre_sz - 1); +} + +void marking_map::put_marking(node_id nid, marking_t const & m) +{ + I(_store.set_if_missing(nid, m)); +} + +void marking_map::put_marking(node_id nid, const_marking_t const & m) +{ + I(_store.set_if_missing(nid, boost::const_pointer_cast(m))); +} + +void marking_map::put_or_replace_marking(node_id nid, marking_t const & m) +{ + _store.set(nid, m); +} + +size_t marking_map::size() const +{ + return _store.size(); +} + +marking_map::const_iterator marking_map::begin() const +{ + return _store.begin(); +} + +marking_map::const_iterator marking_map::end() const +{ + return _store.end(); +} + + node::node(node_id i) : self(i), parent(the_null_node), @@ -1145,7 +1258,6 @@ roster_t::check_sane_against(marking_map void roster_t::check_sane_against(marking_map const & markings, bool temp_nodes_ok) const { - check_sane(temp_nodes_ok); node_map::const_iterator ri; @@ -1155,24 +1267,24 @@ roster_t::check_sane_against(marking_map ri != nodes.end() && mi != markings.end(); ++ri, ++mi) { - I(!null_id(mi->second.birth_revision)); - I(!mi->second.parent_name.empty()); + I(!null_id(mi->second->birth_revision)); + I(!mi->second->parent_name.empty()); if (is_file_t(ri->second)) - I(!mi->second.file_content.empty()); + I(!mi->second->file_content.empty()); else - I(mi->second.file_content.empty()); + I(mi->second->file_content.empty()); attr_map_t::const_iterator rai; map >::const_iterator mai; - for (rai = ri->second->attrs.begin(), mai = mi->second.attrs.begin(); - rai != ri->second->attrs.end() && mai != mi->second.attrs.end(); + for (rai = ri->second->attrs.begin(), mai = mi->second->attrs.begin(); + rai != ri->second->attrs.end() && mai != mi->second->attrs.end(); ++rai, ++mai) { I(rai->first == mai->first); I(!mai->second.empty()); } - I(rai == ri->second->attrs.end() && mai == mi->second.attrs.end()); + I(rai == ri->second->attrs.end() && mai == mi->second->attrs.end()); // TODO: attrs } @@ -1554,102 +1666,138 @@ namespace } void - mark_new_node(revision_id const & new_rid, const_node_t n, marking_t & new_marking) + mark_new_node(revision_id const & new_rid, const_node_t n, marking_map & mm) { - new_marking.birth_revision = new_rid; - I(new_marking.parent_name.empty()); - new_marking.parent_name.insert(new_rid); - I(new_marking.file_content.empty()); + marking_t new_marking(new marking()); + new_marking->birth_revision = new_rid; + I(new_marking->parent_name.empty()); + new_marking->parent_name.insert(new_rid); + I(new_marking->file_content.empty()); if (is_file_t(n)) - new_marking.file_content.insert(new_rid); - I(new_marking.attrs.empty()); + new_marking->file_content.insert(new_rid); + I(new_marking->attrs.empty()); set singleton; singleton.insert(new_rid); for (attr_map_t::const_iterator i = n->attrs.begin(); i != n->attrs.end(); ++i) - new_marking.attrs.insert(make_pair(i->first, singleton)); + new_marking->attrs.insert(make_pair(i->first, singleton)); + mm.put_marking(n->self, new_marking); } void - mark_unmerged_node(marking_t const & parent_marking, const_node_t parent_n, + mark_unmerged_node(const_marking_t const & parent_marking, + const_node_t parent_n, revision_id const & new_rid, const_node_t n, - marking_t & new_marking) + marking_map & mm) { - // SPEEDUP?: the common case here is that the parent and child nodes are - // exactly identical, in which case the markings are also exactly - // identical. There might be a win in first doing an overall - // comparison/copy, in case it can be better optimized as a block - // comparison and a block copy... + // Our new marking map is initialized as a copy of the parent map. + // So, if nothing's changed, there's nothing to do. Unless this + // is a merge, and the parent marking that was copied happens to + // be the other parent than the one this node came from. + if (n == parent_n || shallow_equal(n, parent_n, true)) + { + if (mm.contains(n->self)) + { + return; + } + else + { + mm.put_marking(n->self, parent_marking); + return; + } + } I(same_type(parent_n, n) && parent_n->self == n->self); - new_marking.birth_revision = parent_marking.birth_revision; + marking_t new_marking(new marking()); - mark_unmerged_scalar(parent_marking.parent_name, + new_marking->birth_revision = parent_marking->birth_revision; + + mark_unmerged_scalar(parent_marking->parent_name, make_pair(parent_n->parent, parent_n->name), new_rid, make_pair(n->parent, n->name), - new_marking.parent_name); + new_marking->parent_name); if (is_file_t(n)) - mark_unmerged_scalar(parent_marking.file_content, + mark_unmerged_scalar(parent_marking->file_content, downcast_to_file_t(parent_n)->content, new_rid, downcast_to_file_t(n)->content, - new_marking.file_content); + new_marking->file_content); for (attr_map_t::const_iterator i = n->attrs.begin(); i != n->attrs.end(); ++i) { - set & new_marks = new_marking.attrs[i->first]; + set & new_marks = new_marking->attrs[i->first]; I(new_marks.empty()); attr_map_t::const_iterator j = parent_n->attrs.find(i->first); if (j == parent_n->attrs.end()) new_marks.insert(new_rid); else - mark_unmerged_scalar(safe_get(parent_marking.attrs, i->first), + mark_unmerged_scalar(safe_get(parent_marking->attrs, i->first), j->second, new_rid, i->second, new_marks); } + + mm.put_or_replace_marking(n->self, new_marking); } void - mark_merged_node(marking_t const & left_marking, + mark_merged_node(const_marking_t const & left_marking, set const & left_uncommon_ancestors, const_node_t ln, - marking_t const & right_marking, + const_marking_t const & right_marking, set const & right_uncommon_ancestors, const_node_t rn, revision_id const & new_rid, const_node_t n, - marking_t & new_marking) + marking_map & mm) { + bool same_nodes = ((ln == rn || shallow_equal(ln, rn, true)) && + (ln == n || shallow_equal(ln, n, true))); + if (same_nodes) + { + bool same_markings = left_marking == right_marking + || *left_marking == *right_marking; + if (same_markings) + { + // The child marking will be the same as both parent markings, + // so just leave it as whichever it was copied from. + return; + } + } + I(same_type(ln, n) && same_type(rn, n)); - I(left_marking.birth_revision == right_marking.birth_revision); - new_marking.birth_revision = left_marking.birth_revision; + I(left_marking->birth_revision == right_marking->birth_revision); + marking_t new_marking = mm.get_marking_for_update(n->self); + new_marking->birth_revision = left_marking->birth_revision; MM(n->self); // name - mark_merged_scalar(left_marking.parent_name, left_uncommon_ancestors, + new_marking->parent_name.clear(); + mark_merged_scalar(left_marking->parent_name, left_uncommon_ancestors, make_pair(ln->parent, ln->name), - right_marking.parent_name, right_uncommon_ancestors, + right_marking->parent_name, right_uncommon_ancestors, make_pair(rn->parent, rn->name), new_rid, make_pair(n->parent, n->name), - new_marking.parent_name); + new_marking->parent_name); // content if (is_file_t(n)) { const_file_t f = downcast_to_file_t(n); const_file_t lf = downcast_to_file_t(ln); const_file_t rf = downcast_to_file_t(rn); - mark_merged_scalar(left_marking.file_content, left_uncommon_ancestors, + new_marking->file_content.clear(); + mark_merged_scalar(left_marking->file_content, left_uncommon_ancestors, lf->content, - right_marking.file_content, right_uncommon_ancestors, + right_marking->file_content, right_uncommon_ancestors, rf->content, - new_rid, f->content, new_marking.file_content); + new_rid, f->content, new_marking->file_content); } // attrs + new_marking->attrs.clear(); for (attr_map_t::const_iterator i = n->attrs.begin(); i != n->attrs.end(); ++i) { @@ -1657,11 +1805,11 @@ namespace MM(key); attr_map_t::const_iterator li = ln->attrs.find(key); attr_map_t::const_iterator ri = rn->attrs.find(key); - I(new_marking.attrs.find(key) == new_marking.attrs.end()); + I(new_marking->attrs.find(key) == new_marking->attrs.end()); // [], when used to refer to a non-existent element, default // constructs that element and returns a reference to it. We make use // of this here. - set & new_marks = new_marking.attrs[key]; + set & new_marks = new_marking->attrs[key]; if (li == ln->attrs.end() && ri == rn->attrs.end()) // this is a brand new attribute, never before seen @@ -1669,22 +1817,22 @@ namespace else if (li != ln->attrs.end() && ri == rn->attrs.end()) // only the left side has seen this attr before - mark_unmerged_scalar(safe_get(left_marking.attrs, key), + mark_unmerged_scalar(safe_get(left_marking->attrs, key), li->second, new_rid, i->second, new_marks); else if (li == ln->attrs.end() && ri != rn->attrs.end()) // only the right side has seen this attr before - mark_unmerged_scalar(safe_get(right_marking.attrs, key), + mark_unmerged_scalar(safe_get(right_marking->attrs, key), ri->second, new_rid, i->second, new_marks); else // both sides have seen this attr before - mark_merged_scalar(safe_get(left_marking.attrs, key), + mark_merged_scalar(safe_get(left_marking->attrs, key), left_uncommon_ancestors, li->second, - safe_get(right_marking.attrs, key), + safe_get(right_marking->attrs, key), right_uncommon_ancestors, ri->second, new_rid, i->second, new_marks); @@ -1703,6 +1851,39 @@ namespace I(n->attrs.find(i->first) != n->attrs.end()); } + void drop_extra_markings(roster_t const & ros, marking_map & mm) + { + if (mm.size() > ros.all_nodes().size()) + { + std::set to_drop; + + marking_map::const_iterator mi = mm.begin(), me = mm.end(); + node_map::const_iterator ri = ros.all_nodes().begin(), re = ros.all_nodes().end(); + + for (; mi != me; ++mi) + { + if (ri == re) + { + to_drop.insert(mi->first); + } + else + { + if (ri->first < mi->first) + ++ri; + I(ri == re || ri->first >= mi->first); + if (ri == re || ri->first > mi->first) + to_drop.insert(mi->first); + } + } + for (std::set::const_iterator i = to_drop.begin(); + i != to_drop.end(); ++i) + { + mm.remove_marking(*i); + } + } + I(mm.size() == ros.all_nodes().size()); + } + } // anonymous namespace @@ -1720,6 +1901,15 @@ mark_merge_roster(roster_t const & left_ roster_t const & merge, marking_map & new_markings) { + { + int left_err = left_markings.size() - merge.all_nodes().size(); + int right_err = right_markings.size() - merge.all_nodes().size(); + if (left_err * left_err > right_err * right_err) + new_markings = right_markings; + else + new_markings = left_markings; + } + for (node_map::const_iterator i = merge.all_nodes().begin(); i != merge.all_nodes().end(); ++i) { @@ -1730,40 +1920,38 @@ mark_merge_roster(roster_t const & left_ bool exists_in_left = (left_node); bool exists_in_right = (right_node); - marking_t new_marking; - if (!exists_in_left && !exists_in_right) - mark_new_node(new_rid, n, new_marking); + mark_new_node(new_rid, n, new_markings); else if (!exists_in_left && exists_in_right) { - marking_t const & right_marking = safe_get(right_markings, n->self); + const_marking_t const & right_marking = right_markings.get_marking(n->self); // must be unborn on the left (as opposed to dead) - I(right_uncommon_ancestors.find(right_marking.birth_revision) + I(right_uncommon_ancestors.find(right_marking->birth_revision) != right_uncommon_ancestors.end()); mark_unmerged_node(right_marking, right_node, - new_rid, n, new_marking); + new_rid, n, new_markings); } else if (exists_in_left && !exists_in_right) { - marking_t const & left_marking = safe_get(left_markings, n->self); + const_marking_t const & left_marking = left_markings.get_marking(n->self); // must be unborn on the right (as opposed to dead) - I(left_uncommon_ancestors.find(left_marking.birth_revision) + I(left_uncommon_ancestors.find(left_marking->birth_revision) != left_uncommon_ancestors.end()); mark_unmerged_node(left_marking, left_node, - new_rid, n, new_marking); + new_rid, n, new_markings); } else { - mark_merged_node(safe_get(left_markings, n->self), + mark_merged_node(left_markings.get_marking(n->self), left_uncommon_ancestors, left_node, - safe_get(right_markings, n->self), + right_markings.get_marking(n->self), right_uncommon_ancestors, right_node, - new_rid, n, new_marking); + new_rid, n, new_markings); } + } - safe_insert(new_markings, make_pair(i->first, new_marking)); - } + drop_extra_markings(merge, new_markings); } namespace { @@ -1782,17 +1970,16 @@ namespace { virtual node_id detach_node(file_path const & src) { node_id nid = this->editable_roster_base::detach_node(src); - marking_map::iterator marking = markings.find(nid); - I(marking != markings.end()); - marking->second.parent_name.clear(); - marking->second.parent_name.insert(rid); + marking_t marking = markings.get_marking_for_update(nid); + marking->parent_name.clear(); + marking->parent_name.insert(rid); return nid; } virtual void drop_detached_node(node_id nid) { this->editable_roster_base::drop_detached_node(nid); - safe_erase(markings, nid); + markings.remove_marking(nid); } virtual node_id create_dir_node() @@ -1810,10 +1997,9 @@ namespace { { this->editable_roster_base::apply_delta(pth, old_id, new_id); node_id nid = r.get_node(pth)->self; - marking_map::iterator marking = markings.find(nid); - I(marking != markings.end()); - marking->second.file_content.clear(); - marking->second.file_content.insert(rid); + marking_t marking = markings.get_marking_for_update(nid); + marking->file_content.clear(); + marking->file_content.insert(rid); } virtual void clear_attr(file_path const & path, attr_key const & key) @@ -1832,24 +2018,22 @@ namespace { node_id handle_new(node_id nid) { const_node_t n = r.get_node(nid); - marking_t new_marking; - mark_new_node(rid, n, new_marking); - safe_insert(markings, make_pair(nid, new_marking)); + mark_new_node(rid, n, markings); return nid; } void handle_attr(file_path const & pth, attr_key const & name) { node_id nid = r.get_node(pth)->self; - marking_map::iterator marking = markings.find(nid); - map >::iterator am = marking->second.attrs.find(name); - if (am == marking->second.attrs.end()) + marking_t marking = markings.get_marking_for_update(nid); + map >::iterator am = marking->attrs.find(name); + if (am == marking->attrs.end()) { - marking->second.attrs.insert(make_pair(name, set())); - am = marking->second.attrs.find(name); + marking->attrs.insert(make_pair(name, set())); + am = marking->attrs.find(name); } - I(am != marking->second.attrs.end()); + I(am != marking->attrs.end()); am->second.clear(); am->second.insert(rid); } @@ -1995,20 +2179,20 @@ mark_roster_with_one_parent(roster_t con MM(child_markings); I(!null_id(child_rid)); - child_markings.clear(); + child_markings = parent_markings; for (node_map::const_iterator i = child.all_nodes().begin(); i != child.all_nodes().end(); ++i) { marking_t new_marking; if (parent.has_node(i->first)) - mark_unmerged_node(safe_get(parent_markings, i->first), + mark_unmerged_node(parent_markings.get_marking(i->first), parent.get_node(i->first), - child_rid, i->second, new_marking); + child_rid, i->second, child_markings); else - mark_new_node(child_rid, i->second, new_marking); - safe_insert(child_markings, make_pair(i->first, new_marking)); + mark_new_node(child_rid, i->second, child_markings); } + drop_extra_markings(child, child_markings); child.check_sane_against(child_markings, true); } @@ -2180,8 +2364,12 @@ equal_up_to_renumbering(roster_t const & return false; } // nodes match, check the markings too - if (!(safe_get(a_markings, i->first) == safe_get(b_markings, b_n->self))) - return false; + const_marking_t am = a_markings.get_marking(i->first); + const_marking_t bm = b_markings.get_marking(b_n->self); + if (!(am == bm) && !(*am == *bm)) + { + return false; + } } return true; } @@ -2489,19 +2677,19 @@ push_marking(string & contents, void push_marking(string & contents, bool is_file, - marking_t const & mark, + const_marking_t const & mark, int symbol_length) { - I(!null_id(mark.birth_revision)); + I(!null_id(mark->birth_revision)); contents.append(symbol_length - 5, ' '); contents.append("birth ["); - contents.append(encode_hexenc(mark.birth_revision.inner()(), origin::internal)); + contents.append(encode_hexenc(mark->birth_revision.inner()(), origin::internal)); contents.append("]\n"); - for (set::const_iterator i = mark.parent_name.begin(); - i != mark.parent_name.end(); ++i) + for (set::const_iterator i = mark->parent_name.begin(); + i != mark->parent_name.end(); ++i) { contents.append(symbol_length - 9, ' '); contents.append("path_mark ["); @@ -2511,8 +2699,8 @@ push_marking(string & contents, if (is_file) { - for (set::const_iterator i = mark.file_content.begin(); - i != mark.file_content.end(); ++i) + for (set::const_iterator i = mark->file_content.begin(); + i != mark->file_content.end(); ++i) { contents.append("content_mark [");// always the longest symbol contents.append(encode_hexenc(i->inner()(), origin::internal)); @@ -2520,10 +2708,10 @@ push_marking(string & contents, } } else - I(mark.file_content.empty()); + I(mark->file_content.empty()); - for (map >::const_iterator i = mark.attrs.begin(); - i != mark.attrs.end(); ++i) + for (map >::const_iterator i = mark->attrs.begin(); + i != mark->attrs.end(); ++i) { for (set::const_iterator j = i->second.begin(); j != i->second.end(); ++j) @@ -2550,21 +2738,21 @@ parse_marking(basic_io::parser & pa, { pa.sym(); pa.hex(rev); - marking.birth_revision = + marking->birth_revision = decode_hexenc_as(rev, pa.tok.in.made_from); } else if (pa.symp(syms::path_mark)) { pa.sym(); pa.hex(rev); - safe_insert(marking.parent_name, + safe_insert(marking->parent_name, decode_hexenc_as(rev, pa.tok.in.made_from)); } else if (pa.symp(basic_io::syms::content_mark)) { pa.sym(); pa.hex(rev); - safe_insert(marking.file_content, + safe_insert(marking->file_content, decode_hexenc_as(rev, pa.tok.in.made_from)); } else if (pa.symp(syms::attr_mark)) @@ -2574,7 +2762,7 @@ parse_marking(basic_io::parser & pa, pa.str(k); pa.hex(rev); attr_key key = attr_key(k, pa.tok.in.made_from); - safe_insert(marking.attrs[key], + safe_insert(marking->attrs[key], decode_hexenc_as(rev, pa.tok.in.made_from)); } else break; @@ -2742,9 +2930,8 @@ roster_t::print_to(data & dat, } } - marking_map::const_iterator m = mm.find(curr->self); - I(m != mm.end()); - push_marking(contents, is_file_t(curr), m->second, symbol_length); + const_marking_t m = mm.get_marking(curr->self); + push_marking(contents, is_file_t(curr), m, symbol_length); } } dat = data(contents, origin::internal); @@ -2859,8 +3046,9 @@ roster_t::parse_from(basic_io::parser & } { - marking_t & m(safe_insert(mm, make_pair(n->self, marking_t()))->second); + marking_t m(new marking()); parse_marking(pa, m); + mm.put_marking(n->self, m); } } } ============================================================ --- roster.hh d537c98290349bdd63a111cd0afafe39d3a9992d +++ roster.hh 1b812efa037dd26dc72daa3e5ef41497a91a64bb @@ -146,14 +146,17 @@ template <> void dump(node_t const & n, template <> void dump(node_t const & n, std::string & out); -struct marking_t +struct marking { + u32 cow_version; revision_id birth_revision; std::set parent_name; std::set file_content; std::map > attrs; - marking_t() {}; - bool operator==(marking_t const & other) const + marking(); + marking(marking const & other); + marking const & operator=(marking const & other); + bool operator==(marking const & other) const { return birth_revision == other.birth_revision && parent_name == other.parent_name @@ -162,6 +165,35 @@ struct marking_t } }; +class marking_map +{ + mutable u32 cow_version; + typedef cow_trie map_type; + map_type _store; +public: + typedef map_type::key_type key_type; + typedef map_type::value_type value_type; + + marking_map(); + marking_map(marking_map const & other); + marking_map const & operator=(marking_map const & other); + const_marking_t get_marking(node_id nid) const; + marking_t const & get_marking_for_update(node_id nid); + void put_marking(node_id nid, marking_t const & m); + void put_marking(node_id nid, const_marking_t const & m); + + // for roster_delta + void put_or_replace_marking(node_id nid, marking_t const & m); + + typedef map_type::const_iterator const_iterator; + const_iterator begin() const; + const_iterator end() const; + size_t size() const; + bool contains(node_id nid) const; + void clear(); + void remove_marking(node_id nid); +}; + template <> void dump(std::set const & revids, std::string & out); template <> void dump(marking_t const & marking, std::string & out); template <> void dump(marking_map const & marking_map, std::string & out); @@ -468,7 +500,7 @@ void push_marking(std::string & contents void append_with_escaped_quotes(std::string & collection, std::string const & item); void push_marking(std::string & contents, - bool is_file, marking_t const & mark, + bool is_file, const_marking_t const & mark, int symbol_length); void parse_marking(basic_io::parser & pa, marking_t & marking); ============================================================ --- roster_delta.cc 5225677470dde8755581d7ae22081845ac428e60 +++ roster_delta.cc 8d4fa4dc893653cd5f5a4575af1e96d7e03ef0b6 @@ -116,10 +116,14 @@ namespace // And finally, update the marking map. for (nodes_deleted_t::const_iterator i = nodes_deleted.begin(); i != nodes_deleted.end(); ++i) - safe_erase(markings, *i); + { + markings.remove_marking(*i); + } for (markings_changed_t::const_iterator i = markings_changed.begin(); i != markings_changed.end(); ++i) - markings[i->first] = i->second; + { + markings.put_or_replace_marking(i->first, i->second); + } } void @@ -363,7 +367,7 @@ namespace for (roster_delta_t::markings_changed_t::const_iterator i = d.markings_changed.begin(); i != d.markings_changed.end(); ++i) { - bool is_file = !i->second.file_content.empty(); + bool is_file = !i->second->file_content.empty(); int symbol_length = (is_file ? 12 : 9); push_nid(syms::marking, i->first, contents, symbol_length); push_marking(contents, is_file, i->second, symbol_length); @@ -475,7 +479,7 @@ namespace { parser.sym(); node_id nid = parse_nid(parser); - marking_t m; + marking_t m(new marking()); parse_marking(parser, m); safe_insert(d.markings_changed, make_pair(nid, m)); } @@ -527,7 +531,7 @@ try_get_markings_from_roster_delta(roste bool try_get_markings_from_roster_delta(roster_delta const & del, node_id const & nid, - marking_t & markings) + const_marking_t & markings) { roster_delta_t d; read_roster_delta(del, d); ============================================================ --- roster_delta.hh 8a78d49fa1d7b16ef457cf04367e97d052d1afcb +++ roster_delta.hh e4eb1ea53028db1e8f75aefc9ccf41c2cb00afa6 @@ -28,7 +28,7 @@ try_get_markings_from_roster_delta(roste bool try_get_markings_from_roster_delta(roster_delta const & del, node_id const & nid, - marking_t & markings); + const_marking_t & markings); // See the comment on this function's body for a description of its api. bool ============================================================ --- unit-tests/merge_roster.cc 3a677e1cd5654fa5e41b1e1eee4708a8c2069fb0 +++ unit-tests/merge_roster.cc fd6d157c77b4f168bdc1ed29940beea69707e1a3 @@ -190,10 +190,10 @@ struct base_scalar { r.create_dir_node(nid); r.attach_node(nid, file_path_internal(name)); - marking_t marking; - marking.birth_revision = root_rid; - marking.parent_name.insert(root_rid); - safe_insert(markings, make_pair(nid, marking)); + marking_t m(new marking()); + m->birth_revision = root_rid; + m->parent_name.insert(root_rid); + markings.put_marking(nid, m); } void @@ -201,11 +201,11 @@ struct base_scalar { r.create_file_node(arbitrary_file, nid); r.attach_node(nid, file_path_internal(name)); - marking_t marking; - marking.birth_revision = root_rid; - marking.parent_name.insert(root_rid); - marking.file_content.insert(root_rid); - safe_insert(markings, make_pair(nid, marking)); + marking_t m(new marking()); + m->birth_revision = root_rid; + m->parent_name.insert(root_rid); + m->file_content.insert(root_rid); + markings.put_marking(nid, m); } void @@ -309,7 +309,7 @@ struct basename_scalar : public name_sha this->T::make_thing(r, markings); r.detach_node(this->T::thing_name); r.attach_node(thing_nid, path_for(val)); - markings.find(thing_nid)->second.parent_name = marks; + markings.get_marking_for_update(thing_nid)->parent_name = marks; } virtual ~basename_scalar() {} @@ -342,7 +342,7 @@ struct parent_scalar : public virtual na make_dir("b", b_dir_nid, r, markings); r.detach_node(this->T::thing_name); r.attach_node(thing_nid, path_for(val)); - markings.find(thing_nid)->second.parent_name = marks; + markings.get_marking_for_update(thing_nid)->parent_name = marks; } virtual ~parent_scalar() {} @@ -363,7 +363,7 @@ struct attr_scalar : public virtual base { this->T::make_thing(r, markings); r.set_attr(this->T::thing_name, attr_key("test_key"), attr_value_for(val)); - markings.find(thing_nid)->second.attrs[attr_key("test_key")] = marks; + markings.get_marking_for_update(thing_nid)->attrs[attr_key("test_key")] = marks; } void @@ -414,7 +414,7 @@ struct file_content_scalar : public virt { make_thing(r, markings); downcast_to_file_t(r.get_node_for_update(thing_name))->content = content_for(val); - markings.find(thing_nid)->second.file_content = marks; + markings.get_marking_for_update(thing_nid)->file_content = marks; } void @@ -606,10 +606,10 @@ make_dir(roster_t & r, marking_map & mar { r.create_dir_node(nid); r.attach_node(nid, file_path_internal(name)); - marking_t marking; - marking.birth_revision = birth_rid; - marking.parent_name.insert(parent_name_rid); - safe_insert(markings, make_pair(nid, marking)); + marking_t m(new marking()); + m->birth_revision = birth_rid; + m->parent_name.insert(parent_name_rid); + markings.put_marking(nid, m); } static void @@ -621,11 +621,11 @@ make_file(roster_t & r, marking_map & ma { r.create_file_node(content, nid); r.attach_node(nid, file_path_internal(name)); - marking_t marking; - marking.birth_revision = birth_rid; - marking.parent_name.insert(parent_name_rid); - marking.file_content.insert(file_content_rid); - safe_insert(markings, make_pair(nid, marking)); + marking_t m(new marking()); + m->birth_revision = birth_rid; + m->parent_name.insert(parent_name_rid); + m->file_content.insert(file_content_rid); + markings.put_marking(nid, m); } static void @@ -720,29 +720,29 @@ UNIT_TEST(attr_lifecycle) // marks on them safe_insert(left_roster.get_node_for_update(dir_nid)->attrs, make_pair(attr_key("left_live"), make_pair(true, attr_value("left_live")))); - safe_insert(left_markings[dir_nid].attrs, make_pair(attr_key("left_live"), left_revs)); + safe_insert(left_markings.get_marking_for_update(dir_nid)->attrs, make_pair(attr_key("left_live"), left_revs)); safe_insert(left_roster.get_node_for_update(dir_nid)->attrs, make_pair(attr_key("left_dead"), make_pair(false, attr_value("")))); - safe_insert(left_markings[dir_nid].attrs, make_pair(attr_key("left_dead"), left_revs)); + safe_insert(left_markings.get_marking_for_update(dir_nid)->attrs, make_pair(attr_key("left_dead"), left_revs)); safe_insert(left_roster.get_node_for_update(file_nid)->attrs, make_pair(attr_key("left_live"), make_pair(true, attr_value("left_live")))); - safe_insert(left_markings[file_nid].attrs, make_pair(attr_key("left_live"), left_revs)); + safe_insert(left_markings.get_marking_for_update(file_nid)->attrs, make_pair(attr_key("left_live"), left_revs)); safe_insert(left_roster.get_node_for_update(file_nid)->attrs, make_pair(attr_key("left_dead"), make_pair(false, attr_value("")))); - safe_insert(left_markings[file_nid].attrs, make_pair(attr_key("left_dead"), left_revs)); + safe_insert(left_markings.get_marking_for_update(file_nid)->attrs, make_pair(attr_key("left_dead"), left_revs)); safe_insert(right_roster.get_node_for_update(dir_nid)->attrs, make_pair(attr_key("right_live"), make_pair(true, attr_value("right_live")))); - safe_insert(right_markings[dir_nid].attrs, make_pair(attr_key("right_live"), right_revs)); + safe_insert(right_markings.get_marking_for_update(dir_nid)->attrs, make_pair(attr_key("right_live"), right_revs)); safe_insert(right_roster.get_node_for_update(dir_nid)->attrs, make_pair(attr_key("right_dead"), make_pair(false, attr_value("")))); - safe_insert(right_markings[dir_nid].attrs, make_pair(attr_key("right_dead"), right_revs)); + safe_insert(right_markings.get_marking_for_update(dir_nid)->attrs, make_pair(attr_key("right_dead"), right_revs)); safe_insert(right_roster.get_node_for_update(file_nid)->attrs, make_pair(attr_key("right_live"), make_pair(true, attr_value("right_live")))); - safe_insert(right_markings[file_nid].attrs, make_pair(attr_key("right_live"), right_revs)); + safe_insert(right_markings.get_marking_for_update(file_nid)->attrs, make_pair(attr_key("right_live"), right_revs)); safe_insert(right_roster.get_node_for_update(file_nid)->attrs, make_pair(attr_key("right_dead"), make_pair(false, attr_value("")))); - safe_insert(right_markings[file_nid].attrs, make_pair(attr_key("right_dead"), right_revs)); + safe_insert(right_markings.get_marking_for_update(file_nid)->attrs, make_pair(attr_key("right_dead"), right_revs)); roster_merge_result result; MM(result); @@ -933,7 +933,7 @@ struct simple_invalid_name_conflict : pu bad_dir_nid = nis.next(); left_roster.drop_detached_node(left_roster.detach_node(file_path())); - safe_erase(left_markings, root_nid); + left_markings.remove_marking(root_nid); make_dir(left_roster, left_markings, old_rid, left_rid, "", new_root_nid); make_dir(right_roster, right_markings, old_rid, old_rid, "root_to_be", new_root_nid); @@ -967,7 +967,7 @@ struct simple_missing_root_dir : public other_root_nid = nis.next(); left_roster.drop_detached_node(left_roster.detach_node(file_path())); - safe_erase(left_markings, root_nid); + left_markings.remove_marking(root_nid); make_dir(left_roster, left_markings, old_rid, old_rid, "", other_root_nid); } @@ -1111,7 +1111,7 @@ struct multiple_name_plus_invalid_name : new_root_nid = nis.next(); make_dir(left_roster, left_markings, old_rid, old_rid, "new_root", new_root_nid); right_roster.drop_detached_node(right_roster.detach_node(file_path())); - safe_erase(right_markings, root_nid); + right_markings.remove_marking(root_nid); make_dir(right_roster, right_markings, old_rid, right_rid, "", new_root_nid); make_multiple_name_conflict("new_root/_MTN", "foo"); } @@ -1134,12 +1134,12 @@ struct multiple_name_plus_missing_root : right_root_nid = nis.next(); left_roster.drop_detached_node(left_roster.detach_node(file_path())); - safe_erase(left_markings, root_nid); + left_markings.remove_marking(root_nid); make_dir(left_roster, left_markings, old_rid, left_rid, "", left_root_nid); make_dir(left_roster, left_markings, old_rid, left_rid, "right_root", right_root_nid); right_roster.drop_detached_node(right_roster.detach_node(file_path())); - safe_erase(right_markings, root_nid); + right_markings.remove_marking(root_nid); make_dir(right_roster, right_markings, old_rid, right_rid, "", right_root_nid); make_dir(right_roster, right_markings, old_rid, right_rid, "left_root", left_root_nid); } @@ -1188,11 +1188,11 @@ struct duplicate_name_plus_missing_root right_root_nid = nis.next(); left_roster.drop_detached_node(left_roster.detach_node(file_path())); - safe_erase(left_markings, root_nid); + left_markings.remove_marking(root_nid); make_dir(left_roster, left_markings, left_rid, left_rid, "", left_root_nid); right_roster.drop_detached_node(right_roster.detach_node(file_path())); - safe_erase(right_markings, root_nid); + right_markings.remove_marking(root_nid); make_dir(right_roster, right_markings, right_rid, right_rid, "", right_root_nid); } virtual void check() ============================================================ --- unit-tests/roster.cc 98207c6ccf55333e5407e3c32be85876426e34d6 +++ unit-tests/roster.cc 1d30d48443ab1cd3dc6ace38fbdca7aa3b3ef488 @@ -22,6 +22,25 @@ using boost::shared_ptr; using std::search; using boost::shared_ptr; + +static bool operator==(marking_map const & a, marking_map const & b) +{ + if (a.size() != b.size()) + return false; + marking_map::const_iterator ai = a.begin(); + marking_map::const_iterator bi = b.begin(); + while (ai != a.end()) + { + if (ai->first != bi->first) + return false; + if (!(*ai->second == *bi->second)) + return false; + ++ai; + ++bi; + } + return true; +} + static void make_fake_marking_for(roster_t const & r, marking_map & mm) { @@ -31,9 +50,7 @@ make_fake_marking_for(roster_t const & r for (node_map::const_iterator i = r.all_nodes().begin(); i != r.all_nodes().end(); ++i) { - marking_t fake_marks; - mark_new_node(rid, i->second, fake_marks); - mm.insert(make_pair(i->first, fake_marks)); + mark_new_node(rid, i->second, mm); } } @@ -797,10 +814,10 @@ namespace { roster.create_dir_node(root_nid); roster.attach_node(root_nid, file_path_internal("")); - marking_t marking; - marking.birth_revision = old_rid; - marking.parent_name.insert(old_rid); - safe_insert(markings, make_pair(root_nid, marking)); + marking_t m(new marking()); + m->birth_revision = old_rid; + m->parent_name.insert(old_rid); + markings.put_marking(root_nid, m); } virtual string my_type() const = 0; @@ -835,10 +852,10 @@ namespace roster_t & roster, marking_map & markings) { roster.create_file_node(fid, nid); - marking_t marking; - marking.birth_revision = scalar_origin_rid; - marking.parent_name = marking.file_content = singleton(scalar_origin_rid); - safe_insert(markings, make_pair(nid, marking)); + marking_t m(new marking()); + m->birth_revision = scalar_origin_rid; + m->parent_name = m->file_content = singleton(scalar_origin_rid); + markings.put_marking(nid, m); } }; @@ -848,10 +865,10 @@ namespace roster_t & roster, marking_map & markings) { roster.create_dir_node(nid); - marking_t marking; - marking.birth_revision = scalar_origin_rid; - marking.parent_name = singleton(scalar_origin_rid); - safe_insert(markings, make_pair(nid, marking)); + marking_t m(new marking()); + m->birth_revision = scalar_origin_rid; + m->parent_name = singleton(scalar_origin_rid); + markings.put_marking(nid, m); } }; @@ -888,7 +905,7 @@ namespace safe_get(values, val), roster, markings); roster.attach_node(obj_under_test_nid, file_path_internal("foo")); - markings[obj_under_test_nid].file_content = this_scalar_mark; + markings.get_marking_for_update(obj_under_test_nid)->file_content = this_scalar_mark; } roster.check_sane_against(markings); } @@ -917,7 +934,7 @@ namespace { T::make_obj(scalar_origin_rid, obj_under_test_nid, roster, markings); roster.attach_node(obj_under_test_nid, safe_get(values, val)); - markings[obj_under_test_nid].parent_name = this_scalar_mark; + markings.get_marking_for_update(obj_under_test_nid)->parent_name = this_scalar_mark; } roster.check_sane_against(markings); } @@ -946,12 +963,12 @@ namespace roster.attach_node(b_nid, file_path_internal("dir_b")); roster.create_dir_node(c_nid); roster.attach_node(c_nid, file_path_internal("dir_c")); - marking_t marking; - marking.birth_revision = old_rid; - marking.parent_name.insert(old_rid); - safe_insert(markings, make_pair(a_nid, marking)); - safe_insert(markings, make_pair(b_nid, marking)); - safe_insert(markings, make_pair(c_nid, marking)); + marking_t m(new marking()); + m->birth_revision = old_rid; + m->parent_name.insert(old_rid); + markings.put_marking(a_nid, m); + markings.put_marking(b_nid, m); + markings.put_marking(c_nid, m); } virtual void set(revision_id const & scalar_origin_rid, scalar_val val, @@ -964,7 +981,7 @@ namespace { T::make_obj(scalar_origin_rid, obj_under_test_nid, roster, markings); roster.attach_node(obj_under_test_nid, safe_get(values, val)); - markings[obj_under_test_nid].parent_name = this_scalar_mark; + markings.get_marking_for_update(obj_under_test_nid)->parent_name = this_scalar_mark; } roster.check_sane_against(markings); } @@ -999,7 +1016,7 @@ namespace { safe_insert(roster.get_node_for_update(obj_under_test_nid)->attrs, make_pair(attr_key("test_key"), safe_get(values, val))); - markings[obj_under_test_nid].attrs[attr_key("test_key")] = this_scalar_mark; + markings.get_marking_for_update(obj_under_test_nid)->attrs[attr_key("test_key")] = this_scalar_mark; } roster.check_sane_against(markings); } @@ -1032,7 +1049,7 @@ namespace roster.attach_node(obj_under_test_nid, file_path_internal("foo")); safe_insert(roster.get_node_for_update(obj_under_test_nid)->attrs, make_pair(attr_key("test_key"), safe_get(values, val))); - markings[obj_under_test_nid].attrs[attr_key("test_key")] = this_scalar_mark; + markings.get_marking_for_update(obj_under_test_nid)->attrs[attr_key("test_key")] = this_scalar_mark; } roster.check_sane_against(markings); } @@ -1555,7 +1572,7 @@ namespace { safe_insert(roster.get_node_for_update(obj_under_test_nid)->attrs, make_pair(attr_key("test_key"), safe_get(values, val))); - markings[obj_under_test_nid].attrs[attr_key("test_key")] = this_scalar_mark; + markings.get_marking_for_update(obj_under_test_nid)->attrs[attr_key("test_key")] = this_scalar_mark; } roster.check_sane_against(markings); } @@ -1623,18 +1640,18 @@ UNIT_TEST(die_die_die_merge) // left roster is empty except for the root left_roster.attach_node(left_roster.create_dir_node(nis), file_path()); - marking_t an_old_marking; - an_old_marking.birth_revision = old_rid; - an_old_marking.parent_name = singleton(old_rid); - safe_insert(left_markings, make_pair(left_roster.root()->self, - an_old_marking)); + marking_t an_old_marking(new marking()); + an_old_marking->birth_revision = old_rid; + an_old_marking->parent_name = singleton(old_rid); + left_markings.put_marking(left_roster.root()->self, an_old_marking); + // right roster is identical, except for a dir created in the old rev right_roster = left_roster; right_markings = left_markings; right_roster.attach_node(right_roster.create_dir_node(nis), file_path_internal("foo")); - safe_insert(right_markings, make_pair(right_roster.get_node(file_path_internal("foo"))->self, - an_old_marking)); + right_markings.put_marking(right_roster.get_node(file_path_internal("foo"))->self, + an_old_marking); left_roster.check_sane_against(left_markings); right_roster.check_sane_against(right_markings); @@ -1680,11 +1697,10 @@ UNIT_TEST(same_nid_diff_type) roster_t dir_roster; MM(dir_roster); marking_map dir_markings; MM(dir_markings); dir_roster.attach_node(dir_roster.create_dir_node(nis), file_path()); - marking_t marking; - marking.birth_revision = old_rid; - marking.parent_name = singleton(old_rid); - safe_insert(dir_markings, make_pair(dir_roster.root()->self, - marking)); + marking_t m(new marking()); + m->birth_revision = old_rid; + m->parent_name = singleton(old_rid); + dir_markings.put_marking(dir_roster.root()->self, marking_t(new marking(*m))); roster_t file_roster; MM(file_roster); marking_map file_markings; MM(file_markings); @@ -1695,12 +1711,12 @@ UNIT_TEST(same_nid_diff_type) node_id nid = nis.next(); dir_roster.create_dir_node(nid); dir_roster.attach_node(nid, file_path_internal("foo")); - safe_insert(dir_markings, make_pair(nid, marking)); + dir_markings.put_marking(nid, marking_t(new marking(*m))); file_roster.create_file_node(new_ident(rng), nid); file_roster.attach_node(nid, file_path_internal("foo")); - marking.file_content = singleton(old_rid); - safe_insert(file_markings, make_pair(nid, marking)); + m->file_content = singleton(old_rid); + file_markings.put_marking(nid, marking_t(new marking(*m))); dir_roster.check_sane_against(dir_markings); file_roster.check_sane_against(file_markings); @@ -1757,42 +1773,42 @@ UNIT_TEST(write_roster) nid = nis.next(); r.create_dir_node(nid); r.attach_node(nid, root); - mark_new_node(rid, r.get_node(nid), mm[nid]); + mark_new_node(rid, r.get_node(nid), mm); nid = nis.next(); r.create_dir_node(nid); r.attach_node(nid, foo); - mark_new_node(rid, r.get_node(nid), mm[nid]); + mark_new_node(rid, r.get_node(nid), mm); nid = nis.next(); r.create_dir_node(nid); r.attach_node(nid, xx); r.set_attr(xx, attr_key("say"), attr_value("hello")); - mark_new_node(rid, r.get_node(nid), mm[nid]); + mark_new_node(rid, r.get_node(nid), mm); nid = nis.next(); r.create_dir_node(nid); r.attach_node(nid, fo); - mark_new_node(rid, r.get_node(nid), mm[nid]); + mark_new_node(rid, r.get_node(nid), mm); // check that files aren't ordered separately to dirs & vice versa nid = nis.next(); r.create_file_node(f1, nid); r.attach_node(nid, foo_bar); r.set_attr(foo_bar, attr_key("fascist"), attr_value("tidiness")); - mark_new_node(rid, r.get_node(nid), mm[nid]); + mark_new_node(rid, r.get_node(nid), mm); nid = nis.next(); r.create_dir_node(nid); r.attach_node(nid, foo_ang); - mark_new_node(rid, r.get_node(nid), mm[nid]); + mark_new_node(rid, r.get_node(nid), mm); nid = nis.next(); r.create_dir_node(nid); r.attach_node(nid, foo_zoo); r.set_attr(foo_zoo, attr_key("regime"), attr_value("new")); r.clear_attr(foo_zoo, attr_key("regime")); - mark_new_node(rid, r.get_node(nid), mm[nid]); + mark_new_node(rid, r.get_node(nid), mm); { // manifest first @@ -1904,12 +1920,12 @@ UNIT_TEST(check_sane_against) nid = nis.next(); r.create_dir_node(nid); r.attach_node(nid, root); - mark_new_node(rid, r.get_node(nid), mm[nid]); + mark_new_node(rid, r.get_node(nid), mm); nid = nis.next(); r.create_dir_node(nid); r.attach_node(nid, foo); - mark_new_node(rid, r.get_node(nid), mm[nid]); + mark_new_node(rid, r.get_node(nid), mm); nid = nis.next(); r.create_dir_node(nid); @@ -1927,17 +1943,17 @@ UNIT_TEST(check_sane_against) nid = nis.next(); r.create_dir_node(nid); r.attach_node(nid, root); - mark_new_node(rid, r.get_node(nid), mm[nid]); + mark_new_node(rid, r.get_node(nid), mm); nid = nis.next(); r.create_dir_node(nid); r.attach_node(nid, foo); - mark_new_node(rid, r.get_node(nid), mm[nid]); + mark_new_node(rid, r.get_node(nid), mm); nid = nis.next(); r.create_dir_node(nid); r.attach_node(nid, bar); - mark_new_node(rid, r.get_node(nid), mm[nid]); + mark_new_node(rid, r.get_node(nid), mm); r.detach_node(bar); UNIT_TEST_CHECK_THROW(r.check_sane_against(mm), logic_error); @@ -1951,13 +1967,13 @@ UNIT_TEST(check_sane_against) nid = nis.next(); r.create_dir_node(nid); r.attach_node(nid, root); - mark_new_node(rid, r.get_node(nid), mm[nid]); + mark_new_node(rid, r.get_node(nid), mm); nid = nis.next(); r.create_dir_node(nid); r.attach_node(nid, foo); - mark_new_node(rid, r.get_node(nid), mm[nid]); - mm[nid].birth_revision = revision_id(); + mark_new_node(rid, r.get_node(nid), mm); + mm.get_marking_for_update(nid)->birth_revision = revision_id(); UNIT_TEST_CHECK_THROW(r.check_sane_against(mm), logic_error); } @@ -1970,13 +1986,13 @@ UNIT_TEST(check_sane_against) nid = nis.next(); r.create_dir_node(nid); r.attach_node(nid, root); - mark_new_node(rid, r.get_node(nid), mm[nid]); + mark_new_node(rid, r.get_node(nid), mm); nid = nis.next(); r.create_dir_node(nid); r.attach_node(nid, foo); - mark_new_node(rid, r.get_node(nid), mm[nid]); - mm[nid].parent_name.clear(); + mark_new_node(rid, r.get_node(nid), mm); + mm.get_marking_for_update(nid)->parent_name.clear(); UNIT_TEST_CHECK_THROW(r.check_sane_against(mm), logic_error); } @@ -1989,13 +2005,13 @@ UNIT_TEST(check_sane_against) nid = nis.next(); r.create_dir_node(nid); r.attach_node(nid, root); - mark_new_node(rid, r.get_node(nid), mm[nid]); + mark_new_node(rid, r.get_node(nid), mm); nid = nis.next(); r.create_file_node(f1, nid); r.attach_node(nid, foo); - mark_new_node(rid, r.get_node(nid), mm[nid]); - mm[nid].file_content.clear(); + mark_new_node(rid, r.get_node(nid), mm); + mm.get_marking_for_update(nid)->file_content.clear(); UNIT_TEST_CHECK_THROW(r.check_sane_against(mm), logic_error); } @@ -2008,13 +2024,13 @@ UNIT_TEST(check_sane_against) nid = nis.next(); r.create_dir_node(nid); r.attach_node(nid, root); - mark_new_node(rid, r.get_node(nid), mm[nid]); + mark_new_node(rid, r.get_node(nid), mm); nid = nis.next(); r.create_dir_node(nid); r.attach_node(nid, foo); - mark_new_node(rid, r.get_node(nid), mm[nid]); - mm[nid].file_content.insert(rid); + mark_new_node(rid, r.get_node(nid), mm); + mm.get_marking_for_update(nid)->file_content.insert(rid); UNIT_TEST_CHECK_THROW(r.check_sane_against(mm), logic_error); } @@ -2028,7 +2044,7 @@ UNIT_TEST(check_sane_against) r.create_dir_node(nid); r.attach_node(nid, root); // NB: mark and _then_ add attr - mark_new_node(rid, r.get_node(nid), mm[nid]); + mark_new_node(rid, r.get_node(nid), mm); r.set_attr(root, attr_key("my_key"), attr_value("my_value")); UNIT_TEST_CHECK_THROW(r.check_sane_against(mm), logic_error); @@ -2043,8 +2059,8 @@ UNIT_TEST(check_sane_against) r.create_dir_node(nid); r.attach_node(nid, root); r.set_attr(root, attr_key("my_key"), attr_value("my_value")); - mark_new_node(rid, r.get_node(nid), mm[nid]); - mm[nid].attrs[attr_key("my_key")].clear(); + mark_new_node(rid, r.get_node(nid), mm); + mm.get_marking_for_update(nid)->attrs[attr_key("my_key")].clear(); UNIT_TEST_CHECK_THROW(r.check_sane_against(mm), logic_error); } @@ -2058,8 +2074,8 @@ UNIT_TEST(check_sane_against) r.create_dir_node(nid); r.attach_node(nid, root); r.set_attr(root, attr_key("my_key"), attr_value("my_value")); - mark_new_node(rid, r.get_node(nid), mm[nid]); - mm[nid].attrs[attr_key("my_second_key")].insert(rid); + mark_new_node(rid, r.get_node(nid), mm); + mm.get_marking_for_update(nid)->attrs[attr_key("my_second_key")].insert(rid); UNIT_TEST_CHECK_THROW(r.check_sane_against(mm), logic_error); } @@ -2202,11 +2218,10 @@ UNIT_TEST(unify_rosters_end_to_end_ids) { has_not_roster.attach_node(has_not_roster.create_dir_node(nis), file_path()); - marking_t root_marking; - root_marking.birth_revision = old_rid; - root_marking.parent_name = singleton(old_rid); - safe_insert(has_not_markings, make_pair(has_not_roster.root()->self, - root_marking)); + marking_t root_marking(new marking()); + root_marking->birth_revision = old_rid; + root_marking->parent_name = singleton(old_rid); + has_not_markings.put_marking(has_not_roster.root()->self, root_marking); } roster_t has_roster = has_not_roster; MM(has_roster); @@ -2215,10 +2230,10 @@ UNIT_TEST(unify_rosters_end_to_end_ids) { new_id = has_roster.create_file_node(my_fid, nis); has_roster.attach_node(new_id, file_path_internal("foo")); - marking_t file_marking; - file_marking.birth_revision = has_rid; - file_marking.parent_name = file_marking.file_content = singleton(has_rid); - safe_insert(has_markings, make_pair(new_id, file_marking)); + marking_t file_marking(new marking()); + file_marking->birth_revision = has_rid; + file_marking->parent_name = file_marking->file_content = singleton(has_rid); + has_markings.put_marking(new_id, file_marking); } cset add_cs; MM(add_cs); @@ -2286,16 +2301,16 @@ UNIT_TEST(unify_rosters_end_to_end_attr_ node_id foo_id; { first_roster.attach_node(first_roster.create_dir_node(nis), file_path()); - marking_t marking; - marking.birth_revision = old_rid; - marking.parent_name = singleton(old_rid); - safe_insert(first_markings, make_pair(first_roster.root()->self, marking)); + marking_t m(new marking()); + m->birth_revision = old_rid; + m->parent_name = singleton(old_rid); + first_markings.put_marking(first_roster.root()->self, m); + m.reset(new marking(*m)); foo_id = first_roster.create_file_node(my_fid, nis); first_roster.attach_node(foo_id, file_path_internal("foo")); - marking.file_content = singleton(old_rid); - safe_insert(first_markings, - make_pair(first_roster.get_node(file_path_internal("foo"))->self, marking)); + m->file_content = singleton(old_rid); + first_markings.put_marking(first_roster.get_node(file_path_internal("foo"))->self, m); } roster_t second_roster = first_roster; MM(second_roster); @@ -2305,24 +2320,23 @@ UNIT_TEST(unify_rosters_end_to_end_attr_ file_path_internal("bar")); safe_insert(second_roster.get_node_for_update(file_path_internal("bar"))->attrs, make_pair(attr_key("testbar"), make_pair(false, attr_value()))); - marking_t marking; - marking.birth_revision = second_rid; - marking.parent_name = marking.file_content = singleton(second_rid); - safe_insert(marking.attrs, + marking_t m(new marking()); + m->birth_revision = second_rid; + m->parent_name = m->file_content = singleton(second_rid); + safe_insert(m->attrs, make_pair(attr_key("testbar"), singleton(second_rid))); - safe_insert(second_markings, - make_pair(second_roster.get_node(file_path_internal("bar"))->self, marking)); + second_markings.put_marking(second_roster.get_node(file_path_internal("bar"))->self, m); } // put in the attrs on foo { safe_insert(first_roster.get_node_for_update(foo_id)->attrs, make_pair(attr_key("testfoo1"), make_pair(false, attr_value()))); - safe_insert(first_markings.find(foo_id)->second.attrs, + safe_insert(first_markings.get_marking_for_update(foo_id)->attrs, make_pair(attr_key("testfoo1"), singleton(first_rid))); safe_insert(second_roster.get_node_for_update(foo_id)->attrs, make_pair(attr_key("testfoo2"), make_pair(false, attr_value()))); - safe_insert(second_markings.find(foo_id)->second.attrs, + safe_insert(second_markings.get_marking_for_update(foo_id)->attrs, make_pair(attr_key("testfoo2"), singleton(second_rid))); }