# # # add_dir "tests/netsync_dry_run" # # add_file "tests/netsync_dry_run/__driver__.lua" # content [9a6da1188ff30933c6e060c0a6fe54cd2dc9ceee] # # patch "cmd_netsync.cc" # from [f3cf1b10c6d49b1438d459f4f35eea59b57de5c2] # to [321f76a5fd979cc6ad642f745d5333437c6abdd0] # # patch "network/netsync_session.cc" # from [1ebe5e1a734cd672fdeb29705edefe6f85a2c125] # to [278f41d23b866913c926d4a6be2b84a3f9df681b] # # patch "network/netsync_session.hh" # from [227867a6d5efdac111d46e129c660fba1c327b4f] # to [b21b6f99547c74e3f02f55fa2ae144b832028fc0] # # patch "refiner.cc" # from [e631259ef17957cc2e44d7b9b956db657b93bcf5] # to [2de8131df2595d5bcff5efe133ca1f768006d38f] # # patch "refiner.hh" # from [76a2230251b87e779d7a938ae9e6982fe69ab105] # to [543f5789aa9f74593f909e4b80cea986639228b4] # # patch "tests/common/netsync.lua" # from [2a0b34f969dc8806e497e2ec53231dfe84111e6d] # to [5b18be9929d1d852a5f931fd9756dd30c197c9c6] # ============================================================ --- refiner.cc e631259ef17957cc2e44d7b9b956db657b93bcf5 +++ refiner.cc 2de8131df2595d5bcff5efe133ca1f768006d38f @@ -157,7 +157,9 @@ refiner::refiner(netcmd_item_type type, queries_in_flight(0), calculated_items_to_send(false), done(false), - items_to_receive(0) + items_to_receive(0), + min_items_to_receive(0), + may_receive_more_than_min(false) { merkle_ptr root = merkle_ptr(new merkle_node()); root->type = type; @@ -282,6 +284,33 @@ refiner::process_refinement_command(refi if (their_node.get_slot_state(slot) == leaf_state) note_item_in_peer(their_node, slot); + // esimate how many items to receive + if (their_node.get_slot_state(slot) != empty_state + && our_node->get_slot_state(slot) != subtree_state) + { + if (our_node->get_slot_state(slot) == empty_state) + { + if (their_node.get_slot_state(slot) == leaf_state) + ++min_items_to_receive; + else + { + min_items_to_receive += 2; + may_receive_more_than_min = true; + } + } + else if (their_node.get_slot_state(slot) == leaf_state) + { + // pair of leaves + id our_slotval, their_slotval; + their_node.get_raw_slot(slot, their_slotval); + our_node->get_raw_slot(slot, our_slotval); + if (our_slotval != their_slotval) + ++min_items_to_receive; + } + // else they have a tree and we have a leaf, in which + // case there will be more queries + } + if (ty == refinement_query) { // This block handles the interesting asymmetric cases of subtree ============================================================ --- refiner.hh 76a2230251b87e779d7a938ae9e6982fe69ab105 +++ refiner.hh 543f5789aa9f74593f909e4b80cea986639228b4 @@ -93,6 +93,10 @@ public: bool done; std::set items_to_send; size_t items_to_receive; + + // Estimate of what items_to_receive will be. + size_t min_items_to_receive; + bool may_receive_more_than_min; }; ============================================================ --- cmd_netsync.cc f3cf1b10c6d49b1438d459f4f35eea59b57de5c2 +++ cmd_netsync.cc 321f76a5fd979cc6ad642f745d5333437c6abdd0 @@ -279,7 +279,7 @@ CMD(push, "push", "", CMD_REF(network), "to the netsync server at the address ADDRESS."), options::opts::max_netsync_version | options::opts::min_netsync_version | options::opts::set_default | options::opts::exclude | - options::opts::keys_to_push) + options::opts::keys_to_push | options::opts::dryrun) { database db(app); key_store keys(app); @@ -296,10 +296,10 @@ CMD_AUTOMATE(push, N_("[URL]\n[ADDRESS[: CMD_AUTOMATE(push, N_("[URL]\n[ADDRESS[:PORTNUMBER] [PATTERN ...]]"), N_("Pushes branches to a netsync server"), "", - options::opts::max_netsync_version | - options::opts::min_netsync_version | - options::opts::set_default | options::opts::exclude | - options::opts::keys_to_push) + options::opts::max_netsync_version | + options::opts::min_netsync_version | + options::opts::set_default | options::opts::exclude | + options::opts::keys_to_push | options::opts::dryrun) { database db(app); key_store keys(app); @@ -320,7 +320,7 @@ CMD(pull, "pull", "", CMD_REF(network), "from the netsync server at the address ADDRESS."), options::opts::max_netsync_version | options::opts::min_netsync_version | options::opts::set_default | options::opts::exclude | - options::opts::auto_update) + options::opts::auto_update | options::opts::dryrun) { database db(app); key_store keys(app); @@ -346,7 +346,8 @@ CMD_AUTOMATE(pull, N_("[URL]\n[ADDRESS[: "", options::opts::max_netsync_version | options::opts::min_netsync_version | - options::opts::set_default | options::opts::exclude) + options::opts::set_default | options::opts::exclude | + options::opts::dryrun) { database db(app); key_store keys(app); @@ -367,7 +368,8 @@ CMD(sync, "sync", "", CMD_REF(network), "with the netsync server at the address ADDRESS."), options::opts::max_netsync_version | options::opts::min_netsync_version | options::opts::set_default | options::opts::exclude | - options::opts::keys_to_push | options::opts::auto_update) + options::opts::keys_to_push | options::opts::auto_update | + options::opts::dryrun) { database db(app); key_store keys(app); @@ -397,7 +399,7 @@ CMD_AUTOMATE(sync, N_("[URL]\n[ADDRESS[: "", options::opts::max_netsync_version | options::opts::min_netsync_version | options::opts::set_default | options::opts::exclude | - options::opts::keys_to_push) + options::opts::keys_to_push | options::opts::dryrun) { database db(app); key_store keys(app); ============================================================ --- tests/common/netsync.lua 2a0b34f969dc8806e497e2ec53231dfe84111e6d +++ tests/common/netsync.lua 5b18be9929d1d852a5f931fd9756dd30c197c9c6 @@ -28,29 +28,38 @@ end check(getstd("common/netsync-hooks_with_notes.lua", "netsync.lua")) end -function netsync.internal.client(srv, oper, pat, n, res) - if n == nil then n = 2 end - if n == 1 then - args = {"--rcfile=netsync.lua", "--keydir=keys", - "--db=test.db", oper, srv.address} - else - args = {"--rcfile=netsync.lua", "--keydir=keys"..n, - "--db=test"..n..".db", oper, srv.address} - end - if type(pat) == "string" then - table.insert(args, pat) - elseif type(pat) == "table" then - for k, v in pairs(pat) do - table.insert(args, v) - end - elseif pat ~= nil then - err("Bad pattern type "..type(pat)) - end - check(mtn(unpack(args)), res, false, false) +function netsync.internal.client(srv, oper, pat, n, res, save_output) + if n == nil then n = 2 end + if n == 1 then + args = {"--rcfile=netsync.lua", "--keydir=keys", + "--db=test.db", oper, srv.address} + else + args = {"--rcfile=netsync.lua", "--keydir=keys"..n, + "--db=test"..n..".db", oper, srv.address} + end + if type(pat) == "string" then + table.insert(args, pat) + elseif type(pat) == "table" then + for k, v in pairs(pat) do + table.insert(args, v) + end + elseif pat ~= nil then + err("Bad pattern type "..type(pat)) + end + if save_output == nil then + save_output = false + end + check(mtn(unpack(args)), res, save_output, save_output) end -function netsync.internal.pull(srv, pat, n, res) srv:client("pull", pat, n, res) end -function netsync.internal.push(srv, pat, n, res) srv:client("push", pat, n, res) end -function netsync.internal.sync(srv, pat, n, res) srv:client("sync", pat, n, res) end +function netsync.internal.pull(srv, pat, n, res, save_output) + srv:client("pull", pat, n, res, save_output) +end +function netsync.internal.push(srv, pat, n, res, save_output) + srv:client("push", pat, n, res, save_output) +end +function netsync.internal.sync(srv, pat, n, res, save_output) + srv:client("sync", pat, n, res, save_output) +end function netsync.start(opts, n, min) if type(opts) == "number" then ============================================================ --- network/netsync_session.cc 1ebe5e1a734cd672fdeb29705edefe6f85a2c125 +++ network/netsync_session.cc 278f41d23b866913c926d4a6be2b84a3f9df681b @@ -99,6 +99,8 @@ netsync_session::netsync_session(session key_refiner(key_item, get_voice(), *this), cert_refiner(cert_item, get_voice(), *this), rev_refiner(revision_item, get_voice(), *this), + is_dry_run(opts.dryrun), + dry_run_keys_refined(false), rev_enumerator(project, *this), initiated_by_server(initiated_by_server) { @@ -435,8 +437,68 @@ bool } bool +netsync_session::dry_run_finished() const +{ + bool all = rev_refiner.done + && cert_refiner.done + && dry_run_keys_refined; + + if (all) + { + if (role != source_role) + { + if (key_refiner.may_receive_more_than_min) + { + P(F("would receive %d revisions, %d certs, and at least %d keys") + % rev_refiner.items_to_receive + % cert_refiner.items_to_receive + % key_refiner.min_items_to_receive); + } + else + { + P(F("would receive %d revisions, %d certs, and %d keys") + % rev_refiner.items_to_receive + % cert_refiner.items_to_receive + % key_refiner.min_items_to_receive); + } + } + if (role != sink_role) + { + P(F("would send %d certs and %d keys") + % cert_refiner.items_to_send.size() + % key_refiner.items_to_send.size()); + P(F("would send %d revisions:") + % rev_refiner.items_to_send.size()); + map branch_counts; + for (set::const_iterator i = rev_refiner.items_to_send.begin(); + i != rev_refiner.items_to_send.end(); ++i) + { + revision_id const rid(*i); + set my_branches; + project.get_revision_branches(rid, my_branches); + for(set::iterator b = my_branches.begin(); + b != my_branches.end(); ++b) + { + ++branch_counts[*b]; + } + } + for (map::iterator i = branch_counts.begin(); + i != branch_counts.end(); ++i) + { + P(F("%9d in branch %s") % i->second % i->first); + } + } + } + + return all; +} + +bool netsync_session::finished_working() const { + if (dry_run_finished()) + return true; + bool all = done_all_refinements() && received_all_items() && queued_all_items() @@ -607,6 +669,11 @@ netsync_session::queue_done_cmd(netcmd_i { string typestr; netcmd_item_type_to_string(type, typestr); + if (is_dry_run && type == key_item) + { + dry_run_keys_refined = true; + return; + } L(FL("queueing 'done' command for %s (%d items)") % typestr % n_items); netcmd cmd(get_version()); ============================================================ --- network/netsync_session.hh 227867a6d5efdac111d46e129c660fba1c327b4f +++ network/netsync_session.hh b21b6f99547c74e3f02f55fa2ae144b832028fc0 @@ -72,6 +72,11 @@ netsync_session: refiner cert_refiner; refiner rev_refiner; + // dry-run info + bool is_dry_run; + bool dry_run_keys_refined; + bool dry_run_finished() const; + // Interface to ancestry grovelling. revision_enumerator rev_enumerator; ============================================================ --- /dev/null +++ tests/netsync_dry_run/__driver__.lua 9a6da1188ff30933c6e060c0a6fe54cd2dc9ceee @@ -0,0 +1,51 @@ +include("common/netsync.lua") +mtn_setup() +netsync.setup() + + +addfile("foo", "bar") +commit("testbranch") +baserev = base_revision() + +addfile("aaa", "aaa") +commit("firstbranch") +check(mtn("up", "-r", baserev), 0, false, false) + +addfile("bbb", "bbb") +commit("secondbranch") + + +srv1 = netsync.start() + +srv1:pull({"--dry-run", "*"}, 2, 0, true) +check(qgrep("receive 3 revisions, 12 certs, and 1 keys", "stderr")) +check(not qgrep("send", "stderr")) + +srv1:pull("{testbranch,firstbranch}", 2) +srv1:pull("{testbranch,secondbranch}", 3) + + +srv2 = netsync.start(2) + +srv2:pull({"--dry-run", "*"}, 3, 0, true) +check(qgrep("receive 1 revisions, 4 certs, and 0 keys", "stderr")) +check(not qgrep("send", "stderr")) + +srv2:push({"--dry-run", "*"}, 3, 0, true) +check(qgrep("send 4 certs and 0 keys", "stderr")) +check(qgrep("send 1 revision", "stderr")) +check(qgrep("1 in branch secondbranch", "stderr")) +check(not qgrep("receive", "stderr")) + +srv2:sync({"--dry-run", "*"}, 3, 0, true) +check(qgrep("receive 1 revisions, 4 certs, and 0 keys", "stderr")) +check(qgrep("send 4 certs and 0 keys", "stderr")) +check(qgrep("send 1 revision", "stderr")) +check(qgrep("1 in branch secondbranch", "stderr")) + +srv2:sync({"*"}, 3, 0, true) +srv2:sync({"--dry-run", "*"}, 3, 0, true) +check(qgrep("receive 0 revisions, 0 certs, and 0 keys", "stderr")) +check(qgrep("send 0 certs and 0 keys", "stderr")) +check(qgrep("send 0 revision", "stderr")) +check(not qgrep("in branch", "stderr")) \ No newline at end of file