# # # patch "annotate.cc" # from [5a6800e885c0746290ab0a6c948b65cbf38a5735] # to [8bf75ac76a3eb4ed208196c5c24d440b1e3a7f3d] # # patch "annotate.hh" # from [1084654578762318227a750310ef3f143d894b12] # to [042ec6df1e82fe99a453c341046089b0ddf8e7a3] # # patch "automate.cc" # from [a44275865d6832ec1f58dd052c98b1a544765845] # to [b0e3a7c388ba135c5df0f383231f4a314799d4d8] # # patch "cmd_files.cc" # from [b50cf2dcd44c507747371c64b7ed16d6263c13c2] # to [1986733a6377cad7b391f4d936f08fa23a0e9224] # # patch "cmd_merging.cc" # from [5dd7f48a07e281a3d3c14bd0b900e5e8b93bb110] # to [32e26ebbac982810c4c5fc5c9f00ba4cf3e9c260] # # patch "cmd_ws_commit.cc" # from [f671792297e86c7af0251135d759e18df9c3794e] # to [786606ead8e18ec1354eedff05c7eef954f660ae] # # patch "merge_conflict.cc" # from [c1332122dbe5e642d32367631265eec9143bb0e3] # to [77fd9f5f1549ea8244367929b275509f50dd875e] # # patch "merge_content.cc" # from [f7ab6793b8cf55a9b1774d8c94386b6df32c2b08] # to [28f95337c83fa6740b5626aebcada3858f0a6900] # # patch "merge_roster.cc" # from [e54910bfbd63ee800962d313e433fc79ad3534c1] # to [2319c20cf791d65ca7c52973e913ffaadf86be3a] # # patch "migrate_ancestry.cc" # from [e4cc99186fd44c7daafe5526cbdaaecf726f8e95] # to [0b324d2c3058e71712a06b1009fa199f04e1bc37] # # patch "restrictions.cc" # from [3400a54059bf7f5bc3a04eac5b646cda56ce8829] # to [2fcb9351d2b307fb087a27844e216be2c45df2bc] # # patch "rev_types.hh" # from [c1fdee9901eb139ca5555184ba21b39dd00e09ce] # to [e7947946c6fef63393faeab7f47159c015c4e4c1] # # patch "roster.cc" # from [bf987c9ad5c5d06dee9c5fcf48e4bbff2798d7ee] # to [100158a2e40e8d0dce1050c991b48b60874e6b98] # # patch "roster.hh" # from [43e645cd02b1aa473fd51628b4965c814caf24b3] # to [d537c98290349bdd63a111cd0afafe39d3a9992d] # # patch "unit-tests/cset.cc" # from [f582b5ef8cbc3ffa8d81da0f071c5c4deb4ff18f] # to [ab8ac222f812e4fa410afb47d6eed776684c0771] # # patch "unit-tests/merge_roster.cc" # from [1853c103dd728750136e85ab5e97f72104fc0d7f] # to [3a677e1cd5654fa5e41b1e1eee4708a8c2069fb0] # # patch "unit-tests/roster.cc" # from [5c45a937a25de81e4fb0c78c4c1059731bb11ac6] # to [98207c6ccf55333e5407e3c32be85876426e34d6] # # patch "work.cc" # from [2367e4a44ee048b8a341f468fe96156c5f3e1eb5] # to [4a27d0c0133f6cc04b06944afe080400095676e2] # ============================================================ --- annotate.cc 5a6800e885c0746290ab0a6c948b65cbf38a5735 +++ annotate.cc 8bf75ac76a3eb4ed208196c5c24d440b1e3a7f3d @@ -820,7 +820,7 @@ void } void -do_annotate (project_t & project, file_t file_node, +do_annotate (project_t & project, const_file_t file_node, revision_id rid, bool just_revs) { L(FL("annotating file %s with content %s in revision %s") ============================================================ --- annotate.hh 1084654578762318227a750310ef3f143d894b12 +++ annotate.hh 042ec6df1e82fe99a453c341046089b0ddf8e7a3 @@ -16,7 +16,7 @@ void class project_t; void -do_annotate(project_t & project, file_t file_node, revision_id rid, +do_annotate(project_t & project, const_file_t file_node, revision_id rid, bool just_revs); #endif // defined __ANNOTATE_HH__ ============================================================ --- automate.cc a44275865d6832ec1f58dd052c98b1a544765845 +++ automate.cc b0e3a7c388ba135c5df0f383231f4a314799d4d8 @@ -542,7 +542,7 @@ static void }; static void -get_node_info(node_t const & node, node_info & info) +get_node_info(const_node_t const & node, node_info & info) { info.exists = true; info.id = node->self; @@ -692,7 +692,7 @@ inventory_determine_corresponding_paths( if (old_roster.has_node(fp)) { - node_t node = old_roster.get_node(fp); + const_node_t node = old_roster.get_node(fp); if (new_roster.has_node(node->self)) { file_path new_path; @@ -707,7 +707,7 @@ inventory_determine_corresponding_paths( if (new_roster.has_node(fp)) { - node_t node = new_roster.get_node(fp); + const_node_t node = new_roster.get_node(fp); if (old_roster.has_node(node->self)) { file_path old_path; @@ -729,7 +729,7 @@ inventory_determine_corresponding_paths( if (old_roster.has_node(fp)) { - node_t node = old_roster.get_node(fp); + const_node_t node = old_roster.get_node(fp); if (new_roster.has_node(node->self)) { file_path new_path; @@ -744,7 +744,7 @@ inventory_determine_corresponding_paths( if (new_roster.has_node(fp)) { - node_t node = new_roster.get_node(fp); + const_node_t node = new_roster.get_node(fp); if (old_roster.has_node(node->self)) { file_path old_path; @@ -942,7 +942,7 @@ inventory_determine_changes(inventory_it // for which we can get the content id of both new and old nodes. if (item.new_node.type == path::file && item.fs_type != path::nonexistent) { - file_t old_file = downcast_to_file_t(old_roster.get_node(item.new_node.id)); + const_file_t old_file = downcast_to_file_t(old_roster.get_node(item.new_node.id)); switch (item.old_node.type) { @@ -963,7 +963,7 @@ inventory_determine_changes(inventory_it } // now look for changed attributes - node_t old_node = old_roster.get_node(item.new_node.id); + const_node_t old_node = old_roster.get_node(item.new_node.id); if (old_node->attrs != item.new_node.attrs) changes.push_back("attrs"); } @@ -989,7 +989,7 @@ inventory_determine_birth(inventory_item revision_id rid; if (old_roster.has_node(item.new_node.id)) { - node_t node = old_roster.get_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; @@ -1893,7 +1893,7 @@ CMD_AUTOMATE(get_content_changed, N_("RE F("file %s is unknown for revision %s") % path % ident); - node_t node = new_roster.get_node(path); + 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; @@ -1961,7 +1961,7 @@ CMD_AUTOMATE(get_corresponding_path, N_( E(new_roster.has_node(path), origin::user, F("file %s is unknown for revision %s") % path % ident); - node_t node = new_roster.get_node(path); + const_node_t node = new_roster.get_node(path); basic_io::printer prt; if (old_roster.has_node(node->self)) { ============================================================ --- cmd_files.cc b50cf2dcd44c507747371c64b7ed16d6263c13c2 +++ cmd_files.cc 1986733a6377cad7b391f4d936f08fa23a0e9224 @@ -186,12 +186,12 @@ CMD(annotate, "annotate", "", CMD_REF(in E(roster.has_node(file), origin::user, F("no such file '%s' in revision '%s'") % file % rid); - node_t node = roster.get_node(file); + const_node_t node = roster.get_node(file); E(is_file_t(node), origin::user, F("'%s' in revision '%s' is not a file") % file % rid); - file_t file_node = downcast_to_file_t(node); + const_file_t file_node = downcast_to_file_t(node); L(FL("annotate for file_id %s") % file_node->self); do_annotate(project, file_node, rid, app.opts.revs_only); } @@ -249,7 +249,7 @@ static void } static void -dump_file(database & db, std::ostream & output, file_id & ident) +dump_file(database & db, std::ostream & output, file_id const & ident) { E(db.file_version_exists(ident), origin::user, F("no file version %s found in database") % ident); @@ -276,11 +276,11 @@ dump_file(database & db, std::ostream & E(roster.has_node(fp), origin::user, F("no file '%s' found in revision '%s'") % fp % rid); - node_t node = roster.get_node(fp); + const_node_t node = roster.get_node(fp); E((!null_node(node->self) && is_file_t(node)), origin::user, F("no file '%s' found in revision '%s'") % fp % rid); - file_t file_node = downcast_to_file_t(node); + const_file_t file_node = downcast_to_file_t(node); dump_file(db, output, file_node->content); } ============================================================ --- cmd_merging.cc 5dd7f48a07e281a3d3c14bd0b900e5e8b93bb110 +++ cmd_merging.cc 32e26ebbac982810c4c5fc5c9f00ba4cf3e9c260 @@ -43,7 +43,7 @@ static void using boost::shared_ptr; static void -add_dormant_attrs(node_t const parent, node_t child) +add_dormant_attrs(const_node_t parent, node_t child) { for (attr_map_t::const_iterator i = parent->attrs.begin(); i != parent->attrs.end(); ++i) @@ -89,9 +89,9 @@ three_way_merge(revision_id const & ance for (node_map::const_iterator i = nodes.begin(); i != nodes.end(); ++i) { if (left_with_attrs.has_node(i->first)) - add_dormant_attrs(i->second, left_with_attrs.get_node(i->first)); + add_dormant_attrs(i->second, left_with_attrs.get_node_for_update(i->first)); if (right_with_attrs.has_node(i->first)) - add_dormant_attrs(i->second, right_with_attrs.get_node(i->first)); + add_dormant_attrs(i->second, right_with_attrs.get_node_for_update(i->first)); } // Mark up the ANCESTOR @@ -673,7 +673,7 @@ CMD(merge_into_dir, "merge_into_dir", "" E(right_roster.has_node(dir), origin::user, F("Path %s not found in destination tree.") % pth); - node_t parent = right_roster.get_node(dir); + const_node_t parent = right_roster.get_node(dir); moved_root->parent = parent->self; moved_root->name = base; marking_map::iterator @@ -1161,8 +1161,8 @@ CMD_AUTOMATE(file_merge, N_("LEFT_REVID content_merge_database_adaptor adaptor(db, left_rid, right_rid, left_marking, right_marking); - file_t left_n = downcast_to_file_t(left_roster.get_node(left_path)); - file_t right_n = downcast_to_file_t(right_roster.get_node(right_path)); + const_file_t left_n = downcast_to_file_t(left_roster.get_node(left_path)); + const_file_t right_n = downcast_to_file_t(right_roster.get_node(right_path)); revision_id ancestor_rid; file_path ancestor_path; ============================================================ --- cmd_ws_commit.cc f671792297e86c7af0251135d759e18df9c3794e +++ cmd_ws_commit.cc 786606ead8e18ec1354eedff05c7eef954f660ae @@ -788,8 +788,7 @@ drop_attr(app_state & app, args_vector c F("Unknown path '%s'") % path); roster_t new_roster = old_roster; - node_t node = new_roster.get_node(path); - new_roster.unshare(node); + node_t node = new_roster.get_node_for_update(path); // Clear all attrs (or a specific attr). if (args.size() == 1) @@ -855,7 +854,7 @@ CMD(attr_get, "get", "", CMD_REF(attr), file_path path = file_path_external(idx(args, 0)); E(new_roster.has_node(path), origin::user, F("Unknown path '%s'") % path); - node_t node = new_roster.get_node(path); + const_node_t node = new_roster.get_node(path); if (args.size() == 1) { @@ -907,8 +906,7 @@ set_attr(app_state & app, args_vector co F("Unknown path '%s'") % path); roster_t new_roster = old_roster; - node_t node = new_roster.get_node(path); - new_roster.unshare(node); + node_t node = new_roster.get_node_for_update(path); attr_key a_key = typecast_vocab(idx(args, 1)); attr_value a_value = typecast_vocab(idx(args, 2)); @@ -992,7 +990,7 @@ CMD_AUTOMATE(get_attributes, N_("PATH"), basic_io::printer pr; // the current node holds all current attributes (unchanged and new ones) - node_t n = current.get_node(path); + const_node_t n = current.get_node(path); for (attr_map_t::const_iterator i = n->attrs.begin(); i != n->attrs.end(); ++i) { @@ -1009,7 +1007,7 @@ CMD_AUTOMATE(get_attributes, N_("PATH"), // in any previous revision I(base.has_node(path)); - node_t prev_node = base.get_node(path); + const_node_t prev_node = base.get_node(path); // find the attribute in there attr_map_t::const_iterator j = prev_node->attrs.find(i->first); @@ -1027,7 +1025,7 @@ CMD_AUTOMATE(get_attributes, N_("PATH"), { if (base.has_node(path)) { - node_t prev_node = base.get_node(path); + const_node_t prev_node = base.get_node(path); attr_map_t::const_iterator j = prev_node->attrs.find(i->first); ============================================================ --- merge_conflict.cc c1332122dbe5e642d32367631265eec9143bb0e3 +++ merge_conflict.cc 77fd9f5f1549ea8244367929b275509f50dd875e @@ -30,7 +30,7 @@ namespace node_type get_type(roster_t const & roster, node_id const nid) { - node_t n = roster.get_node(nid); + const_node_t n = roster.get_node(nid); if (is_file_t(n)) return file_type; @@ -195,7 +195,7 @@ get_nid_name_pair(roster_t const & roste node_id & nid, std::pair & name) { - node_t const node = roster.get_node(file_path_external(utf8(path, origin::internal))); + const_node_t node = roster.get_node(file_path_external(utf8(path, origin::internal))); nid = node->self; name = make_pair (node->parent, node->name); } @@ -2286,7 +2286,7 @@ attach_node (lua_hooks & lua, new_roster.attach_node (nid, target_path); - node_t node = new_roster.get_node (nid); + const_node_t node = new_roster.get_node (nid); for (attr_map_t::const_iterator attr = node->attrs.begin(); attr != node->attrs.end(); ++attr) @@ -2390,7 +2390,7 @@ resolve_duplicate_name_one_side(lua_hook result_data = file_data(result_raw_data); calculate_ident(result_data, result_fid); - file_t result_node = downcast_to_file_t(result_roster.get_node(nid)); + file_t result_node = downcast_to_file_t(result_roster.get_node_for_update(nid)); result_node->content = result_fid; adaptor.record_file(fid, result_fid, parent_data, result_data); @@ -2404,7 +2404,7 @@ resolve_duplicate_name_one_side(lua_hook if (is_dir_t(result_roster.get_node(nid))) { - dir_t n = downcast_to_dir_t(result_roster.get_node(nid)); + const_dir_t n = downcast_to_dir_t(result_roster.get_node(nid)); E(n->children.empty(), origin::user, F("can't drop %s; not empty") % name); } result_roster.drop_detached_node(nid); @@ -2537,7 +2537,7 @@ roster_merge_result::resolve_file_conten P(F("merged %s, %s") % left_name % right_name); - file_t result_node = downcast_to_file_t(roster.get_node(conflict.nid)); + file_t result_node = downcast_to_file_t(roster.get_node_for_update(conflict.nid)); result_node->content = merged_id; } break; @@ -2558,7 +2558,7 @@ roster_merge_result::resolve_file_conten result_data = file_data(result_raw_data); calculate_ident(result_data, result_id); - file_t result_node = downcast_to_file_t(roster.get_node(conflict.nid)); + file_t result_node = downcast_to_file_t(roster.get_node_for_update(conflict.nid)); result_node->content = result_id; adaptor.record_merge(conflict.left, conflict.right, result_id, ============================================================ --- merge_content.cc f7ab6793b8cf55a9b1774d8c94386b6df32c2b08 +++ merge_content.cc 28f95337c83fa6740b5626aebcada3858f0a6900 @@ -634,7 +634,7 @@ try_to_merge_files(lua_hooks & lua, { L(FL("resolved content conflict %d / %d on file '%s'") % cnt % total_conflicts % right_path); - file_t f = downcast_to_file_t(result.roster.get_node(conflict.nid)); + file_t f = downcast_to_file_t(result.roster.get_node_for_update(conflict.nid)); f->content = merged_id; it = result.file_content_conflicts.erase(it); ============================================================ --- merge_roster.cc e54910bfbd63ee800962d313e433fc79ad3534c1 +++ merge_roster.cc 2319c20cf791d65ca7c52973e913ffaadf86be3a @@ -411,7 +411,7 @@ namespace return; } - dir_t p = downcast_to_dir_t(result.roster.get_node(parent)); + dir_t p = downcast_to_dir_t(result.roster.get_node_for_update(parent)); // duplicate name conflict: // see the comment in roster_merge.hh for the analysis showing that at ============================================================ --- migrate_ancestry.cc e4cc99186fd44c7daafe5526cbdaaecf726f8e95 +++ migrate_ancestry.cc 0b324d2c3058e71712a06b1009fa199f04e1bc37 @@ -503,10 +503,10 @@ insert_into_roster(roster_t & child_rost { if (child_roster.has_node(pth)) { - node_t n = child_roster.get_node(pth); + const_node_t n = child_roster.get_node(pth); E(is_file_t(n), origin::internal, F("Path %s cannot be added, as there is a directory in the way") % pth); - file_t f = downcast_to_file_t(n); + const_file_t f = downcast_to_file_t(n); E(f->content == fid, origin::internal, F("Path %s added twice with differing content") % pth); return; @@ -597,8 +597,8 @@ anc_graph::fixup_node_identities(parent_ if ((!child_roster.has_node(n)) && child_roster.has_node(fp)) { - node_t pn = parent_roster->get_node(n); - node_t cn = child_roster.get_node(fp); + const_node_t pn = parent_roster->get_node(n); + const_node_t cn = child_roster.get_node(fp); if (is_file_t(pn) == is_file_t(cn)) { child_roster.replace_node_id(cn->self, n); ============================================================ --- restrictions.cc 3400a54059bf7f5bc3a04eac5b646cda56ce8829 +++ restrictions.cc 2fcb9351d2b307fb087a27844e216be2c45df2bc @@ -275,7 +275,7 @@ node_restriction::includes(roster_t cons } } - node_t node = roster.get_node(current); + const_node_t node = roster.get_node(current); current = node->parent; path_depth++; } ============================================================ --- rev_types.hh c1fdee9901eb139ca5555184ba21b39dd00e09ce +++ rev_types.hh e7947946c6fef63393faeab7f47159c015c4e4c1 @@ -75,6 +75,11 @@ typedef boost::shared_ptr dir_ typedef boost::shared_ptr node_t; typedef boost::shared_ptr file_t; typedef boost::shared_ptr dir_t; + +typedef boost::shared_ptr const_node_t; +typedef boost::shared_ptr const_file_t; +typedef boost::shared_ptr const_dir_t; + typedef std::map marking_map; typedef std::map dir_map; ============================================================ --- roster.cc bf987c9ad5c5d06dee9c5fcf48e4bbff2798d7ee +++ roster.cc 100158a2e40e8d0dce1050c991b48b60874e6b98 @@ -328,15 +328,14 @@ dfs_iter struct dfs_iter { - - dir_t root; + const_dir_t root; string curr_path; bool return_root; bool track_path; - stack< pair > stk; + stack< pair > stk; - dfs_iter(dir_t r, bool t = false) + dfs_iter(const_dir_t r, bool t = false) : root(r), return_root(root), track_path(t) { if (root && !root->children.empty()) @@ -357,7 +356,7 @@ dfs_iter } - node_t operator*() const + const_node_t operator*() const { I(!finished()); if (return_root) @@ -374,7 +373,7 @@ private: { int prevsize = 0; int nextsize = 0; - pair & stack_top(stk.top()); + pair & stack_top(stk.top()); if (track_path) { prevsize = stack_top.second->first().size(); @@ -456,14 +455,14 @@ inline bool inline bool -same_type(node_t a, node_t b) +same_type(const_node_t a, const_node_t b) { return is_file_t(a) == is_file_t(b); } inline bool -shallow_equal(node_t a, node_t b, +shallow_equal(const_node_t a, const_node_t b, bool shallow_compare_dir_children, bool compare_file_contents) { @@ -486,16 +485,16 @@ shallow_equal(node_t a, node_t b, { if (compare_file_contents) { - file_t fa = downcast_to_file_t(a); - file_t fb = downcast_to_file_t(b); + const_file_t fa = downcast_to_file_t(a); + const_file_t fb = downcast_to_file_t(b); if (!(fa->content == fb->content)) return false; } } else { - dir_t da = downcast_to_dir_t(a); - dir_t db = downcast_to_dir_t(b); + const_dir_t da = downcast_to_dir_t(a); + const_dir_t db = downcast_to_dir_t(b); if (shallow_compare_dir_children) { @@ -590,12 +589,10 @@ equal_shapes(roster_t const & a, roster_ return true; } -node_t -roster_t::get_node(file_path const & p) const +node_t roster_t::get_node_internal(file_path const & p) const { MM(*this); MM(p); - I(has_root()); if (p.empty()) return root_dir; @@ -619,6 +616,20 @@ roster_t::get_node(file_path const & p) } } +const_node_t +roster_t::get_node(file_path const & p) const +{ + return get_node_internal(p); +} + +node_t +roster_t::get_node_for_update(file_path const & p) +{ + node_t n = get_node_internal(p); + unshare(n); + return n; +} + bool roster_t::has_node(node_id n) const { @@ -641,7 +652,7 @@ roster_t::is_attached(node_id n) const if (!has_node(n)) return false; - node_t node = get_node(n); + const_node_t node = get_node(n); return !null_node(node->parent); } @@ -679,7 +690,7 @@ roster_t::has_node(file_path const & p) } } -node_t +const_node_t roster_t::get_node(node_id nid) const { node_t const &n(nodes.get_if_present(nid)); @@ -687,18 +698,27 @@ roster_t::get_node(node_id nid) const return n; } +node_t +roster_t::get_node_for_update(node_id nid) +{ + node_t n(nodes.get_if_present(nid)); + I(n); + unshare(n); + return n; +} + void roster_t::get_name(node_id nid, file_path & p) const { I(!null_node(nid)); - stack sp; + stack sp; size_t size = 0; while (nid != root_dir->self) { - node_t n = get_node(nid); + const_node_t n = get_node(nid); sp.push(n); size += n->name().length() + 1; nid = n->parent; @@ -768,7 +788,8 @@ roster_t::replace_node_id(node_id from, { I(!null_node(from)); I(!null_node(to)); - node_t n = get_node(from); + node_t n = nodes.get_if_present(from); + I(n); nodes.unset(from); unshare(n, false); @@ -810,8 +831,7 @@ roster_t::detach_node(file_path const & return root_id; } - node_t pp = get_node(dirname); - unshare(pp); + node_t pp = get_node_for_update(dirname); dir_t parent = downcast_to_dir_t(pp); node_t c = parent->get_child(basename); unshare(c); @@ -825,7 +845,7 @@ roster_t::detach_node(node_id nid) void roster_t::detach_node(node_id nid) { - node_t n = get_node(nid); + node_t n = get_node_for_update(nid); if (null_node(n->parent)) { // detaching the root dir @@ -837,10 +857,8 @@ roster_t::detach_node(node_id nid) } else { - unshare(n); path_component name = n->name; - node_t p = get_node(n->parent); - unshare(p); + node_t p = get_node_for_update(n->parent); dir_t parent = downcast_to_dir_t(p); I(parent->detach_child(name) == n); safe_insert(old_locations, @@ -852,7 +870,7 @@ roster_t::drop_detached_node(node_id nid roster_t::drop_detached_node(node_id nid) { // ensure the node is already detached - node_t n = get_node(nid); + const_node_t n = get_node(nid); I(null_node(n->parent)); I(n->name.empty()); // if it's a dir, make sure it's empty @@ -928,7 +946,7 @@ roster_t::attach_node(node_id nid, node_ void roster_t::attach_node(node_id nid, node_id parent, path_component name) { - node_t n = get_node(nid); + node_t n = get_node_for_update(nid); I(!null_node(n->self)); // ensure the node is already detached (as best one can) @@ -952,9 +970,7 @@ roster_t::attach_node(node_id nid, node_ } else { - unshare(n); - node_t p = get_node(parent); - unshare(p); + node_t p = get_node_for_update(parent); dir_t parent_n = downcast_to_dir_t(p); parent_n->attach_child(name, n); I(i == old_locations.end() || i->second != make_pair(n->parent, n->name)); @@ -969,8 +985,7 @@ roster_t::apply_delta(file_path const & file_id const & old_id, file_id const & new_id) { - node_t n = get_node(pth); - unshare(n); + node_t n = get_node_for_update(pth); file_t f = downcast_to_file_t(n); I(f->content == old_id); I(!null_node(f->self)); @@ -981,8 +996,7 @@ roster_t::set_content(node_id nid, file_ void roster_t::set_content(node_id nid, file_id const & new_id) { - node_t n = get_node(nid); - unshare(n); + node_t n = get_node_for_update(nid); file_t f = downcast_to_file_t(n); I(!(f->content == new_id)); f->content = new_id; @@ -1000,8 +1014,7 @@ roster_t::erase_attr(node_id nid, roster_t::erase_attr(node_id nid, attr_key const & name) { - node_t n = get_node(nid); - unshare(n); + node_t n = get_node_for_update(nid); safe_erase(n->attrs, name); } @@ -1019,8 +1032,7 @@ roster_t::set_attr(file_path const & pth attr_key const & name, pair const & val) { - node_t n = get_node(pth); - unshare(n); + node_t n = get_node_for_update(pth); I(val.first || val.second().empty()); I(!null_node(n->self)); attr_map_t::iterator i = n->attrs.find(name); @@ -1037,8 +1049,7 @@ roster_t::set_attr_unknown_to_dead_ok(no attr_key const & name, pair const & val) { - node_t n = get_node(nid); - unshare(n); + node_t n = get_node_for_update(nid); I(val.first || val.second().empty()); attr_map_t::iterator i = n->attrs.find(name); if (i != n->attrs.end()) @@ -1053,7 +1064,7 @@ roster_t::get_attr(file_path const & pth { I(has_node(pth)); - node_t n = get_node(pth); + const_node_t n = get_node(pth); attr_map_t::const_iterator i = n->attrs.find(name); if (i != n->attrs.end() && i->second.first) { @@ -1087,14 +1098,14 @@ roster_t::check_sane(bool temp_nodes_ok) roster_t::check_sane(bool temp_nodes_ok) const { node_id parent_id(the_null_node); - dir_t parent_dir; + const_dir_t parent_dir; I(old_locations.empty()); I(has_root()); size_t maxdepth = nodes.size(); bool is_first = true; for (dfs_iter i(root_dir); !i.finished(); ++i) { - node_t const &n(*i); + const_node_t const &n(*i); if (is_first) { I(n->name.empty() && null_node(n->parent)); @@ -1543,7 +1554,7 @@ namespace } void - mark_new_node(revision_id const & new_rid, node_t n, marking_t & new_marking) + mark_new_node(revision_id const & new_rid, const_node_t n, marking_t & new_marking) { new_marking.birth_revision = new_rid; I(new_marking.parent_name.empty()); @@ -1560,8 +1571,8 @@ namespace } void - mark_unmerged_node(marking_t const & parent_marking, node_t parent_n, - revision_id const & new_rid, node_t n, + mark_unmerged_node(marking_t const & parent_marking, const_node_t parent_n, + revision_id const & new_rid, const_node_t n, marking_t & new_marking) { // SPEEDUP?: the common case here is that the parent and child nodes are @@ -1605,12 +1616,12 @@ namespace void mark_merged_node(marking_t const & left_marking, set const & left_uncommon_ancestors, - node_t ln, + const_node_t ln, marking_t const & right_marking, set const & right_uncommon_ancestors, - node_t rn, + const_node_t rn, revision_id const & new_rid, - node_t n, + const_node_t n, marking_t & new_marking) { I(same_type(ln, n) && same_type(rn, n)); @@ -1629,9 +1640,9 @@ namespace // content if (is_file_t(n)) { - file_t f = downcast_to_file_t(n); - file_t lf = downcast_to_file_t(ln); - file_t rf = downcast_to_file_t(rn); + 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, lf->content, right_marking.file_content, right_uncommon_ancestors, @@ -1820,7 +1831,7 @@ namespace { node_id handle_new(node_id nid) { - node_t n = r.get_node(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)); @@ -2156,7 +2167,7 @@ equal_up_to_renumbering(roster_t const & a.get_name(i->first, p); if (!b.has_node(p)) return false; - node_t b_n = b.get_node(p); + const_node_t b_n = b.get_node(p); // we already know names are the same if (!same_type(i->second, b_n)) return false; @@ -2283,7 +2294,7 @@ make_restricted_roster(roster_t const & else restricted.create_dir_node(n->second->self); - node_t added = restricted.get_node(n->second->self); + node_t added = restricted.get_node_for_update(n->second->self); added->attrs = n->second->attrs; restricted.attach_node(n->second->self, n->second->parent, n->second->name); @@ -2411,7 +2422,7 @@ roster_t::get_file_details(node_id nid, file_path & pth) const { I(has_node(nid)); - file_t f = downcast_to_file_t(get_node(nid)); + const_file_t f = downcast_to_file_t(get_node(nid)); fid = f->content; get_name(nid, pth); } @@ -2438,12 +2449,12 @@ get_content_paths(roster_t const & roste node_map const & nodes = roster.all_nodes(); for (node_map::const_iterator i = nodes.begin(); i != nodes.end(); ++i) { - node_t node = roster.get_node(i->first); + const_node_t node = roster.get_node(i->first); if (is_file_t(node)) { file_path p; roster.get_name(i->first, p); - file_t file = downcast_to_file_t(node); + const_file_t file = downcast_to_file_t(node); paths.insert(make_pair(file->content, p)); } } @@ -2627,7 +2638,7 @@ roster_t::print_to(data & dat, { contents += "\n"; - node_t curr = *i; + const_node_t curr = *i; int symbol_length = 0; @@ -2676,7 +2687,7 @@ roster_t::print_to(data & dat, { symbol_length = 7; } - file_t ftmp = downcast_to_file_t(curr); + const_file_t ftmp = downcast_to_file_t(curr); contents.append(symbol_length - 4, ' '); contents.append("file \""); ============================================================ --- roster.hh 43e645cd02b1aa473fd51628b4965c814caf24b3 +++ roster.hh d537c98290349bdd63a111cd0afafe39d3a9992d @@ -84,13 +84,13 @@ inline bool }; inline bool -is_dir_t(node_t n) +is_dir_t(const_node_t n) { return n->type == node_type_dir; } inline bool -is_file_t(node_t n) +is_file_t(const_node_t n) { return n->type == node_type_file; } @@ -108,24 +108,40 @@ inline dir_t } inline dir_t -downcast_to_dir_t(node_t const n) +downcast_to_dir_t(node_t const & n) { dir_t d = boost::dynamic_pointer_cast(n); I(static_cast(d)); return d; } - inline file_t -downcast_to_file_t(node_t const n) +downcast_to_file_t(node_t const & n) { file_t f = boost::dynamic_pointer_cast(n); I(static_cast(f)); return f; } +inline const_dir_t +downcast_to_dir_t(const_node_t const & n) +{ + const_dir_t d = boost::dynamic_pointer_cast(n); + I(static_cast(d)); + return d; +} + +inline const_file_t +downcast_to_file_t(const_node_t const & n) +{ + const_file_t f = boost::dynamic_pointer_cast(n); + I(static_cast(f)); + return f; +} + bool -shallow_equal(node_t a, node_t b, bool shallow_compare_dir_children, +shallow_equal(const_node_t a, const_node_t b, + bool shallow_compare_dir_children, bool compare_file_contents = true); template <> void dump(node_t const & n, std::string & out); @@ -161,8 +177,13 @@ public: bool has_node(node_id nid) const; bool is_root(node_id nid) const; bool is_attached(node_id nid) const; - node_t get_node(file_path const & sp) const; - node_t get_node(node_id nid) const; +private: + node_t get_node_internal(file_path const & p) const; +public: + const_node_t get_node(file_path const & sp) const; + const_node_t get_node(node_id nid) const; + node_t get_node_for_update(file_path const & sp); + node_t get_node_for_update(node_id nid); void get_name(node_id nid, file_path & sp) const; void unshare(node_t & n, bool is_in_node_map = true); void replace_node_id(node_id from, node_id to); ============================================================ --- unit-tests/cset.cc f582b5ef8cbc3ffa8d81da0f071c5c4deb4ff18f +++ unit-tests/cset.cc ab8ac222f812e4fa410afb47d6eed776684c0771 @@ -410,7 +410,7 @@ UNIT_TEST(basic_csets) attr_value("klang"))); cs.attrs_cleared.insert(make_pair(foo_bar, attr_key("attr_file"))); UNIT_TEST_CHECK_NOT_THROW(cs.apply_to(tree), logic_error); - UNIT_TEST_CHECK((r.get_node(foo_bar))->attrs[attr_key("attr_file")] + UNIT_TEST_CHECK((r.get_node_for_update(foo_bar))->attrs[attr_key("attr_file")] == make_pair(false, attr_value(""))); UNIT_TEST_CHECK(r.all_nodes().size() == 3); } ============================================================ --- unit-tests/merge_roster.cc 1853c103dd728750136e85ab5e97f72104fc0d7f +++ unit-tests/merge_roster.cc 3a677e1cd5654fa5e41b1e1eee4708a8c2069fb0 @@ -374,7 +374,7 @@ struct attr_scalar : public virtual base switch (expected_val) { case scalar_a: case scalar_b: - I(result.roster.get_node(thing_nid)->attrs[attr_key("test_key")] + I(result.roster.get_node_for_update(thing_nid)->attrs[attr_key("test_key")] == make_pair(true, attr_value_for(expected_val))); break; case scalar_conflict: @@ -413,7 +413,7 @@ struct file_content_scalar : public virt roster_t & r, marking_map & markings) { make_thing(r, markings); - downcast_to_file_t(r.get_node(thing_name))->content = content_for(val); + downcast_to_file_t(r.get_node_for_update(thing_name))->content = content_for(val); markings.find(thing_nid)->second.file_content = marks; } @@ -433,7 +433,7 @@ struct file_content_scalar : public virt I(c.nid == thing_nid); I(c.left == content_for(left_val)); I(c.right == content_for(right_val)); - file_id & content = downcast_to_file_t(result.roster.get_node(thing_nid))->content; + file_id & content = downcast_to_file_t(result.roster.get_node_for_update(thing_nid))->content; I(null_id(content)); // resolve the conflict, thus making sure that resolution works and // that this was the only conflict signaled @@ -718,29 +718,29 @@ UNIT_TEST(attr_lifecycle) // put one live and one dead attr on each thing on each side, with uncommon // marks on them - safe_insert(left_roster.get_node(dir_nid)->attrs, + 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_roster.get_node(dir_nid)->attrs, + 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_roster.get_node(file_nid)->attrs, + 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_roster.get_node(file_nid)->attrs, + 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(right_roster.get_node(dir_nid)->attrs, + 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_roster.get_node(dir_nid)->attrs, + 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_roster.get_node(file_nid)->attrs, + 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_roster.get_node(file_nid)->attrs, + 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)); ============================================================ --- unit-tests/roster.cc 5c45a937a25de81e4fb0c78c4c1059731bb11ac6 +++ unit-tests/roster.cc 98207c6ccf55333e5407e3c32be85876426e34d6 @@ -65,7 +65,7 @@ do_testing_on_one_roster(roster_t const { file_path from_iter = file_path_internal(i.path()); file_path from_getname; - node_t curr = *i; + const_node_t curr = *i; r.get_name(curr->self, from_getname); I(from_iter == from_getname); } @@ -616,9 +616,9 @@ UNIT_TEST(check_sane_roster_screwy_dir_m r.attach_node(r.create_dir_node(nis), root); roster_t other; MM(other); node_id other_nid = other.create_dir_node(nis); - dir_t root_n = downcast_to_dir_t(r.get_node(root)); + dir_t root_n = downcast_to_dir_t(r.get_node_for_update(root)); root_n->children.insert(make_pair(path_component("foo"), - other.get_node(other_nid))); + other.get_node_for_update(other_nid))); UNIT_TEST_CHECK_THROW(r.check_sane(), logic_error); // well, but that one was easy, actually, because a dir traversal will hit // more nodes than actually exist... so let's make it harder, by making sure @@ -626,7 +626,7 @@ UNIT_TEST(check_sane_roster_screwy_dir_m node_id distractor_nid = r.create_dir_node(nis); UNIT_TEST_CHECK_THROW(r.check_sane(), logic_error); // and even harder, by making that node superficially valid too - dir_t distractor_n = downcast_to_dir_t(r.get_node(distractor_nid)); + dir_t distractor_n = downcast_to_dir_t(r.get_node_for_update(distractor_nid)); distractor_n->parent = distractor_nid; distractor_n->name = path_component("foo"); distractor_n->children.insert(make_pair(distractor_n->name, distractor_n)); @@ -643,7 +643,7 @@ UNIT_TEST(bad_attr) make_pair(false, attr_value("invalid"))), logic_error); UNIT_TEST_CHECK_NOT_THROW(r.check_sane(true), logic_error); - safe_insert(r.get_node(root)->attrs, + safe_insert(r.get_node_for_update(root)->attrs, make_pair(attr_key("test_key2"), make_pair(false, attr_value("invalid")))); UNIT_TEST_CHECK_THROW(r.check_sane(true), logic_error); @@ -997,7 +997,7 @@ namespace roster.attach_node(obj_under_test_nid, file_path_internal("foo")); if (val != scalar_none) { - safe_insert(roster.get_node(obj_under_test_nid)->attrs, + 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; } @@ -1030,7 +1030,7 @@ namespace { T::make_obj(scalar_origin_rid, obj_under_test_nid, roster, markings); roster.attach_node(obj_under_test_nid, file_path_internal("foo")); - safe_insert(roster.get_node(obj_under_test_nid)->attrs, + 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; } @@ -1553,7 +1553,7 @@ namespace } if (val != scalar_none && val != scalar_none_2) { - safe_insert(roster.get_node(obj_under_test_nid)->attrs, + 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; } @@ -2303,7 +2303,7 @@ UNIT_TEST(unify_rosters_end_to_end_attr_ { second_roster.attach_node(second_roster.create_file_node(my_fid, nis), file_path_internal("bar")); - safe_insert(second_roster.get_node(file_path_internal("bar"))->attrs, + 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; @@ -2316,15 +2316,11 @@ UNIT_TEST(unify_rosters_end_to_end_attr_ // put in the attrs on foo { - node_t n = first_roster.get_node(foo_id); - first_roster.unshare(n); - safe_insert(first_roster.get_node(foo_id)->attrs, + 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, make_pair(attr_key("testfoo1"), singleton(first_rid))); - n = second_roster.get_node(foo_id); - second_roster.unshare(n); - safe_insert(second_roster.get_node(foo_id)->attrs, + 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, make_pair(attr_key("testfoo2"), singleton(second_rid))); ============================================================ --- work.cc 2367e4a44ee048b8a341f468fe96156c5f3e1eb5 +++ work.cc 4a27d0c0133f6cc04b06944afe080400095676e2 @@ -817,9 +817,9 @@ workspace::maybe_update_inodeprints(data roster_t const & parent_ros = parent_roster(parent); if (parent_ros.has_node(nid)) { - node_t old_node = parent_ros.get_node(nid); + const_node_t old_node = parent_ros.get_node(nid); I(is_file_t(old_node)); - file_t old_file = downcast_to_file_t(old_node); + const_file_t old_file = downcast_to_file_t(old_node); if (new_file->content != old_file->content) { @@ -1364,10 +1364,10 @@ simulated_working_tree::drop_detached_no void simulated_working_tree::drop_detached_node(node_id nid) { - node_t node = workspace.get_node(nid); + const_node_t node = workspace.get_node(nid); if (is_dir_t(node)) { - dir_t dir = downcast_to_dir_t(node); + const_dir_t dir = downcast_to_dir_t(node); if (!dir->children.empty()) { map::const_iterator i = nid_map.find(nid); @@ -1781,10 +1781,10 @@ workspace::perform_deletions(database & P(F("skipping %s, not currently tracked") % name); else { - node_t n = new_roster.get_node(name); + const_node_t n = new_roster.get_node(name); if (is_dir_t(n)) { - dir_t d = downcast_to_dir_t(n); + const_dir_t d = downcast_to_dir_t(n); if (!d->children.empty()) { E(recursive, origin::user, @@ -1808,7 +1808,7 @@ workspace::perform_deletions(database & } else { - file_t file = downcast_to_file_t(n); + const_file_t file = downcast_to_file_t(n); file_id fid; I(ident_existing_file(name, fid)); if (file->content == fid) @@ -2072,7 +2072,7 @@ workspace::perform_content_update(roster i = update.deltas_applied.begin(); i != update.deltas_applied.end(); ++i) { - node_t node = new_roster.get_node(i->first); + const_node_t node = new_roster.get_node(i->first); for (attr_map_t::const_iterator a = node->attrs.begin(); a != node->attrs.end(); ++a) {