# # patch "ChangeLog" # from [63c759b0cfd48e65dc585981636065a006a2409e] # to [94df1b3806f6020b5ab486f8e77d0d0789c4c489] # # patch "change_set.cc" # from [39d27129e791256a3b0bba63888179de3fe225c0] # to [62f13b93026c2ca5cae82595101f98f4fbb05d8e] # # patch "pcdv.cc" # from [3bf2c8965080e804a4f70c0e152ef89f34c9bc03] # to [52ca638a980086603d40838ebb861e892a5ff7f3] # # patch "pcdv.hh" # from [729ea8ceeea750b9f559fed0403eba28f3270593] # to [17325b49d29d3b78d11828c7355867d975d63229] # ======================================================================== --- ChangeLog 63c759b0cfd48e65dc585981636065a006a2409e +++ ChangeLog 94df1b3806f6020b5ab486f8e77d0d0789c4c489 @@ -1,3 +1,7 @@ +2005-08-20 Timothy Brownawell + + * pcdv.{cc,hh} (tree merger): each file now gets a versioned scalar + 2005-08-19 Timothy Brownawell * change_set.cc: Add (and use) dump() for vector ======================================================================== --- change_set.cc 39d27129e791256a3b0bba63888179de3fe225c0 +++ change_set.cc 62f13b93026c2ca5cae82595101f98f4fbb05d8e @@ -1654,6 +1654,8 @@ file_path left; file_path right; file_path merged; + bool clean; + file_id hash; itempaths(file_path const & a, file_path const & l, file_path const & r, file_path const & m): @@ -1993,6 +1995,7 @@ // do the merge std::vector conf(l.conflict(r)); + MM(conf); std::set res; for (std::vector::const_iterator i = conf.begin(); i != conf.end(); ++i) ======================================================================== --- pcdv.cc 3bf2c8965080e804a4f70c0e152ef89f34c9bc03 +++ pcdv.cc 52ca638a980086603d40838ebb861e892a5ff7f3 @@ -774,12 +774,18 @@ leaves(), is_dir(false) { - versions->insert(make_pair(revid(-1), - make_pair(make_pair(item_id(-1), - make_null_component()), - vector()))); - std::vector * l = new std::vector(); - l->push_back(revid(-1)); + versions->first.insert(make_pair(revid(-1), + make_pair(make_pair(item_id(-1), + make_null_component()), + vector()))); + versions->second.insert(make_pair(revid(-1), + make_pair(scalar(-1), + vector()))); + std::pair, + std::vector > * l = new std::pair, + std::vector >(); + l->first.push_back(revid(-1)); + l->second.push_back(revid(-1)); leaves.reset(l); } @@ -788,13 +794,19 @@ leaves(), is_dir(false) { - std::vector * l = new std::vector(); - l->push_back(revid(-1)); + versions->first.insert(make_pair(revid(-1), + make_pair(make_pair(item_id(-1), + make_null_component()), + vector()))); + versions->second.insert(make_pair(revid(-1), + make_pair(scalar(-1), + vector()))); + std::pair, + std::vector > * l = new std::pair, + std::vector >(); + l->first.push_back(revid(-1)); + l->second.push_back(revid(-1)); leaves.reset(l); - versions->insert(make_pair(revid(-1), - make_pair(make_pair(item_id(-1), - make_null_component()), - vector()))); } item_status::item_status(item_status const & x): @@ -810,31 +822,36 @@ item_status::copy() const { item_status out(*this); - out.leaves.reset(new std::vector(*leaves)); + out.leaves.reset(new std::pair, + std::vector >(*leaves)); return out; } item_status const -item_status::new_version(vector const & _leaves) const +item_status::new_version(std::pair, + vector > const & _leaves) const { - I(leaves->size()); + I(leaves->first.size() && leaves->second.size()); item_status out(*this); - out.leaves.reset(new vector(_leaves)); + out.leaves.reset(new std::pair, + std::vector >(_leaves)); return out; } -item_status -item_status::merge(item_status const & other) const +template +vector +merge_half(std::map > > & versions, + std::vector const & leaves1, + std::vector const & leaves2) { - I(versions == other.versions); - I(is_dir == other.is_dir); - set leafset, done; + typedef std::map > > data; + std::set leafset, done; std::deque todo; - for (vector::const_iterator i = leaves->begin(); - i != leaves->end(); ++i) + for (vector::const_iterator i = leaves1.begin(); + i != leaves1.end(); ++i) leafset.insert(*i); - for (vector::const_iterator i = other.leaves->begin(); - i != other.leaves->end(); ++i) + for (vector::const_iterator i = leaves2.begin(); + i != leaves2.end(); ++i) leafset.insert(*i); for (set::const_iterator i = leafset.begin(); i != leafset.end(); ++i) @@ -842,8 +859,8 @@ // erase_ancestors(leafset) while (todo.size()) { - item_data::const_iterator i = versions->find(todo.front()); - I(i != versions->end()); + typename data::const_iterator i = versions.find(todo.front()); + I(i != versions.end()); for (vector::const_iterator j = i->second.second.begin(); j != i->second.second.end(); ++j) { @@ -867,6 +884,23 @@ for (set::const_iterator i = leafset.begin(); i != leafset.end(); ++i) newleaves.push_back(*i); + return newleaves; +} + +item_status +item_status::merge(item_status const & other) const +{ + I(versions == other.versions); + I(is_dir == other.is_dir); + std::vector newleaves1, newleaves2; + newleaves1 = merge_half(versions->first, + leaves->first, + other.leaves->first); + newleaves2 = merge_half(versions->second, + leaves->second, + other.leaves->second); + std::pair, std::vector > + newleaves(newleaves1, newleaves2); if (newleaves == *leaves) return *this; if (newleaves == *other.leaves) @@ -874,22 +908,23 @@ return new_version(newleaves); } -item_status -item_status::suture(item_status const & other) const +template +void +suture_maps(std::map > > & v1, + std::map > > const & v2) { - I(versions != other.versions); - I(is_dir == other.is_dir); - for (item_data::iterator o = other.versions->begin(); - o != other.versions->end(); ++o) + typedef std::map > > data; + for (typename data::const_iterator o = v2.begin(); + o != v2.end(); ++o) { - item_data::iterator m = versions->find(o->first); - if (m == versions->end()) - versions->insert(*o); + typename data::iterator m = v1.find(o->first); + if (m == v1.end()) + v1.insert(*o); else { if (!(m->second.first == o->second.first)) { - W(F("Sutured items previously had different names in the same revision.")); + W(F("Sutured items previously had different values in the same revision.")); L(F("This was in revision #%1%") % o->first); } std::set s; @@ -908,23 +943,42 @@ } } } +} + +item_status +item_status::suture(item_status const & other) const +{ + I(versions != other.versions); + I(is_dir == other.is_dir); + suture_maps(versions->first, other.versions->first); + suture_maps(versions->second, other.versions->second); item_status myother(other); myother.versions = versions; return merge(myother); } -std::set -item_status::current_names() const +template +std::set +current_values(std::map > > const & v, + std::vector const & leaves) { - I(leaves->size()); - std::set out; - for (vector::const_iterator i = leaves->begin(); - i != leaves->end(); ++i) + typedef std::map > > data; + std::set out; + for (typename vector::const_iterator i = leaves.begin(); + i != leaves.end(); ++i) { - item_data::const_iterator j = versions->find(*i); - I(j != versions->end()); + typename data::const_iterator j = v.find(*i); + I(j != v.end()); out.insert(j->second.first); } + return out; +} + +std::set +item_status::current_names() const +{ + I(leaves->first.size()); + std::set out = current_values(versions->first, leaves->first); if (out.size() > 1 && out.find(make_pair(-1, make_null_component())) != out.end()) { @@ -934,51 +988,77 @@ return out; } -item_status -item_status::rename(revid rev, item_id new_parent, path_component new_name) const +std::set +item_status::current_scalars() const { - item_state newstate(make_pair(new_parent, new_name)); + I(leaves->second.size()); + return current_values(versions->second, leaves->second); +} + +template +std::vector +change_value(std::map > > & ver, + std::vector const & leaves, T const & val, revid rev, + std::set const & current) +{ + typedef std::map > > data; // { - item_data::iterator i = versions->find(rev); - if (i != versions->end()) + typename data::iterator i = ver.find(rev); + if (i != ver.end()) { // I(i->second.first == newstate); // An error, but it's triggered by errors already in the monotone db. // These are of the form cs_left = {}, cs_right = {drop, add} // So, warn instead of failing. - if (i->second.first == newstate) - return *this; - W(F("Renaming a file to multiple names within one revision.")); + if (i->second.first == val) + return leaves; + W(F("Giving a file multiple values within one revision.")); } // } - vector newleaves, badleaves; + std::vector newleaves, badleaves; newleaves.push_back(rev); - for (vector::const_iterator i = leaves->begin(); - i != leaves->end(); ++i) + for (vector::const_iterator i = leaves.begin(); + i != leaves.end(); ++i) { - item_data::const_iterator j = versions->find(*i); - I(j != versions->end()); - if (j->second.first == newstate) + typename data::const_iterator j = ver.find(*i); + I(j != ver.end()); + if (j->second.first == val) newleaves.push_back(*i); else if (*i != rev) badleaves.push_back(*i); } - if (i != versions->end()) - versions->erase(i); - versions->insert(make_pair(rev, make_pair(newstate, badleaves))); + if (i != ver.end()) + ver.erase(i); + ver.insert(make_pair(rev, make_pair(val, badleaves))); if (badleaves.empty()) - { - std::set c = current_names(); - I(c.size() == 1); - I(*c.begin() == newstate); - return *this; - } + newleaves.erase(newleaves.begin()); + return newleaves; +} - item_status out(new_version(newleaves)); +item_status +item_status::rename(revid rev, item_id new_parent, path_component new_name) const +{ + path_state newstate(make_pair(new_parent, new_name)); + std::vector newleaves = change_value(versions->first, + leaves->first, + newstate, + rev, current_names()); + item_status out(new_version(make_pair(newleaves, leaves->second))); return out; } +item_status +item_status::set_scalar(revid rev, scalar ns) const +{ + std::vector newleaves = change_value(versions->second, + leaves->second, + ns, + rev, current_scalars()); + item_status out(new_version(make_pair(leaves->first, newleaves))); + return out; +} + tree_state::tree_state(): items(new vector >()), states(new std::map()), @@ -1166,7 +1246,7 @@ pi = items->size() - 1; pd = cit.intern(pdir()); outmap.insert(make_pair(pd, pi)); - L(F("New implied directory %1%") % pdir); + L(F("New implied directory %1% (%2%)") % pdir % pi); } } @@ -1213,7 +1293,7 @@ for (std::map::const_iterator j = i->states->begin(); j != i->states->end(); ++j) { - std::set s = j->second.current_names(); + std::set s = j->second.current_names(); I(s.size() == 1); file_path fp = i->get_full_name(*s.begin()); if ((fp == file_path())) @@ -1264,7 +1344,9 @@ std::map::const_iterator j = t.states->find(myid); I(j != t.states->end()); - file_path fp = t.get_full_name(j->second); + std::set s = j->second.current_names(); + I(s.size() == 1); + file_path fp = out.get_full_name(*s.begin()); I(!(fp == file_path())); done.insert(myid); std::pair::iterator, bool> r; @@ -1336,7 +1418,7 @@ I(!(to == file_path())); { int d = -1; - std::set s = current_item.current_names(); + std::set s = current_item.current_names(); file_path orig; if (s.size() == 1) orig = out.try_get_full_name(*s.begin(), d); @@ -1404,7 +1486,9 @@ std::map::const_iterator j = t.states->find(myid); I(j != t.states->end()); - file_path fp = t.get_full_name(j->second); + std::set s = j->second.current_names(); + I(s.size() == 1); + file_path fp = out.get_full_name(*s.begin()); I(!(fp == file_path())); std::pair::iterator, bool> r; r = outmap.insert(make_pair(cit.intern(fp()), myid)); @@ -1472,14 +1556,14 @@ apply_sutures(); tree_state merged(mash(other)); std::vector out; - std::map > m; + std::map > m; // splits, merge(mv a b, mv a c) for (std::map::const_iterator i = merged.states->begin(); i != merged.states->end(); ++i) { - std::set s = i->second.current_names(); + std::set s = i->second.current_names(); if (s.size() != 1) { path_conflict c; @@ -1490,7 +1574,7 @@ k(other.states->find(i->first)); I(j != states->end()); I(k != other.states->end()); - std::set + std::set left(j->second.current_names()), right(k->second.current_names()); I(left.size() == 1); @@ -1499,12 +1583,12 @@ c.rnames.push_back(other.get_full_name(*right.begin())); out.push_back(c); } - for (std::set::const_iterator + for (std::set::const_iterator j = s.begin(); j != s.end(); ++j) { if (*j == make_pair(item_id(-1), make_null_component())) continue; - std::map >::iterator + std::map >::iterator k = m.find(*j); if (k == m.end()) { @@ -1518,7 +1602,7 @@ } // collisions, merge(mv a c, mv b c) - for (std::map >::const_iterator + for (std::map >::const_iterator i = m.begin(); i != m.end(); ++i) { if (i->second.size() == 1) @@ -1533,7 +1617,7 @@ std::map::const_iterator l(states->find(*j)), r(other.states->find(*j)); - std::set left, right; + std::set left, right; if (l != states->end()) { left = l->second.current_names(); @@ -1566,9 +1650,7 @@ { if (i->second.is_dir) continue; - std::set s = i->second.current_names(); - I(s.size() == 1); - file_path fp = get_full_name(*s.begin()); + file_path fp = get_full_name(i->second); if (!(fp == file_path())) out.push_back(make_pair(i->first, fp)); } @@ -1583,9 +1665,7 @@ for (std::map::const_iterator i = states->begin(); i != states->end(); ++i) { - std::set s = i->second.current_names(); - I(s.size() == 1); - file_path fp = get_full_name(*s.begin()); + file_path fp = get_full_name(i->second); if (!(fp == file_path())) out.push_back(make_pair(i->first, fp)); } @@ -1609,12 +1689,12 @@ map::const_iterator l, r; l = states->begin(); r = merged.states->begin(); - item_status::item_state empty(-1, make_null_component()); + item_status::path_state empty(-1, make_null_component()); while (l != states->end() || r != merged.states->end()) { file_path from, to; - std::set pres, posts; - item_status::item_state pre(empty), post(empty); + std::set pres, posts; + item_status::path_state pre(empty), post(empty); bool from_is_dir(false), to_is_dir(false); if (l == states->end()) @@ -1742,7 +1822,7 @@ { if (resolved.find(j->first) == resolved.end()) { - std::set + std::set x(j->second.current_names()); if (x.size() != 1) continue;// not resolved, so not closer @@ -1775,7 +1855,7 @@ if (s == resolved.size()) { // already resolved this item, this resolution had better match - std::set names = it.current_names(); + std::set names = it.current_names(); I(names.size() == 1); file_path prev = merged.get_full_name(*names.begin()); file_path to; @@ -1840,14 +1920,14 @@ file_path tree_state::get_full_name(item_status x) const { - std::set y; + std::set y; y = x.current_names(); I(y.size() == 1); return get_full_name(*y.begin()); } file_path -tree_state::get_full_name(item_status::item_state x) const +tree_state::get_full_name(item_status::path_state x) const { int d; file_path out(try_get_full_name(x, d)); @@ -1856,7 +1936,7 @@ } file_path -tree_state::try_get_full_name(item_status::item_state x, int & d) const +tree_state::try_get_full_name(item_status::path_state x, int & d) const { d = 0; std::vector names; @@ -1866,7 +1946,7 @@ std::map::const_iterator i = states->find(x.first); I(i != states->end()); - std::set y = i->second.current_names(); + std::set y = i->second.current_names(); if (y.size() != 1) { d = -1; @@ -1882,7 +1962,7 @@ } std::string -tree_state::get_ambiguous_full_name(item_status::item_state x) const +tree_state::get_ambiguous_full_name(item_status::path_state x) const { // fails if the item has multiple names (only call this on clean trees) std::vector names; @@ -1894,7 +1974,7 @@ std::map::const_iterator i = states->find(x.first); I(i != states->end()); - std::set y = i->second.current_names(); + std::set y = i->second.current_names(); if (y.size() != 1) { out = (F("/") % x.first).str(); @@ -1909,10 +1989,71 @@ return out; } +tree_state +tree_state::set_scalars(std::string revision, + std::map const & m) const +{ + apply_sutures(); + tree_state out(*this); + std::vector > c = current_with_dirs(); + for (std::vector >::const_iterator + i = c.begin(); i != c.end(); ++i) + { + std::map::const_iterator + j = m.find(i->second); + if (j == m.end()) + continue; + std::map::iterator k = out.states->find(i->first); + I(k != out.states->end()); + k->second = k->second.set_scalar(itx->intern(revision), j->second); + } + return out; +} +std::map > +tree_state::current_scalars() const +{ + apply_sutures(); + std::map > out; + for (std::map::const_iterator i = states->begin(); + i != states->end(); ++i) + out.insert(make_pair(i->first, i->second.current_scalars())); + return out; +} +//////////////////////////// I/O //////////////////////////////////// + +void +dump(path_conflict const & obj, std::string & out) +{ + out = "##########"; + out+=(F("#Type: %1%\n") + % ((obj.type == path_conflict::collision)?"Collision":"Split")).str(); + for (unsigned int j = 0; j < obj.items.size(); ++j) + { + out+=(F("Item %1%:\n") % idx(obj.items, j)).str(); + out+=(F("#\tLname: %1%\n") % idx(obj.lnames, j)).str(); + out+=(F("#\tRname: %1%\n") % idx(obj.rnames, j)).str(); + } + out+=(F("#Name: %1%\n") % obj.name).str(); +} + +void +dump(std::vector const & obj, std::string & out) +{ + out.clear(); + for (std::vector::const_iterator i = obj.begin(); + i != obj.end(); ++i) + { + std::string tmp; + dump(*i, tmp); + out += tmp; + } +} + + ///////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////// /////////////////////////// Tests /////////////////////////////////// ======================================================================== --- pcdv.hh 729ea8ceeea750b9f559fed0403eba28f3270593 +++ pcdv.hh 17325b49d29d3b78d11828c7355867d975d63229 @@ -193,12 +193,16 @@ struct item_status { - typedef std::pair item_state; - typedef std::map > > item_data; + typedef unsigned int scalar; + typedef std::pair path_state; + typedef std::map > > path_data; + typedef std::map > > scalar_data; + typedef std::pair item_data; // shared for all versions of this item boost::shared_ptr versions; // shared between all copies of this version of this item - boost::shared_ptr const > leaves; + boost::shared_ptr, + std::vector > const> leaves; bool is_dir; item_status(); @@ -208,7 +212,8 @@ ~item_status(); item_status const - new_version(vector const & _leaves) const; + new_version(std::pair, + std::vector > const & _leaves) const; item_status merge(item_status const & other) const; @@ -216,13 +221,19 @@ item_status suture(item_status const & other) const; - std::set + std::set current_names() const; + std::set + current_scalars() const; + item_status rename(revid rev, item_id new_parent, path_component new_name) const; item_status + set_scalar(revid rev, scalar ns) const; + + item_status copy() const; }; @@ -268,8 +279,15 @@ std::vector const & changes, std::string revision); + tree_state + set_scalars(std::string revision, + std::map const & m) const; + std::vector conflict(tree_state const & other) const; + + std::map > + current_scalars() const; bool is_clean() @@ -292,16 +310,16 @@ std::string const & revision); private: file_path - get_full_name(item_status::item_state x) const; + get_full_name(item_status::path_state x) const; file_path get_full_name(item_status x) const; file_path - try_get_full_name(item_status::item_state x, int & d) const; + try_get_full_name(item_status::path_state x, int & d) const; std::string - get_ambiguous_full_name(item_status::item_state x) const; + get_ambiguous_full_name(item_status::path_state x) const; tree_state mash(tree_state const & other) const; @@ -317,6 +335,12 @@ }; void +dump(path_conflict const & obj, std::string & out); + +void +dump(std::vector const & obj, std::string & out); + +void dirmerge_test(); #endif