# # # patch "database.cc" # from [b37f89c9d264b674728fda144360e30d5d3b6397] # to [809e62c9dd0adcd5c4d86d4f863bcb29f203ceaa] # # patch "database.hh" # from [7eb9a59905d0c790a5f76cb6fd1c35b538b7af60] # to [688a9e65e619589ed8536495986505623dfb2dd1] # # patch "graph.cc" # from [2d934cb225b5639919fec3eda0cbec615cf2f903] # to [fc6bcec20a325cc94d936a718437558e0489078d] # # patch "graph.hh" # from [6384f6bd01b8b43383ba2e6adf6ae10b6f725bac] # to [a463fb39255436e51b39d02c3488bd2e349a0fdc] # # patch "rcs_import.cc" # from [f6ce4f02b7f5e254f6be4e5e98739fce77b62947] # to [5a6ffafdc0f791e90bc5cd2627e9262210731358] # # patch "schema.sql" # from [c093f206468fcc6663167a57258c07adb9c33880] # to [8102b2a148c8c9220db03d8cd79ffb89ccd549c6] # # patch "schema_migration.cc" # from [769321d3bb854322d9de25354e9e240396cf1096] # to [49bd56dbd04ea1bd9156aac3c7642af398db4064] # ============================================================ --- database.cc b37f89c9d264b674728fda144360e30d5d3b6397 +++ database.cc 809e62c9dd0adcd5c4d86d4f863bcb29f203ceaa @@ -781,17 +781,22 @@ database::fetch(results & res, { string log; switch (query.args[param-1].type) - { + { // FIXME: this is somewhat ugly... case query_param::text: - case query_param::blob: log = query.args[param-1].data; + if (log.size() > constants::log_line_sz) + log = log.substr(0, constants::log_line_sz); + L(FL("binding %d with value '%s'") % param % log); break; + case query_param::blob: + log = encode_hexenc(query.args[param-1].data); + if (log.size() > constants::log_line_sz) + log = log.substr(0, constants::log_line_sz); + L(FL("binding %d with value x'%s'") % param % log); + break; + default: + L(FL("binding %d with unknown type") % param); } - - if (log.size() > constants::log_line_sz) - log = log.substr(0, constants::log_line_sz); - - L(FL("binding %d with value '%s'") % param % log); } switch (idx(query.args, param - 1).type) @@ -849,12 +854,12 @@ bool } bool -database::table_has_entry(std::string const & key, std::string const & column, +database::table_has_entry(hexenc const & key, std::string const & column, std::string const & table) { results res; query q("SELECT 1 FROM " + table + " WHERE " + column + " = ? LIMIT 1"); - fetch(res, one_col, any_rows, q % text(key)); + fetch(res, one_col, any_rows, q % blob(decode_hexenc(key()))); return !res.empty(); } @@ -932,7 +937,7 @@ database::drop_or_cancel_file(file_id co if (have_delayed_file(id)) cancel_delayed_file(id); else - drop(id.inner()(), "files"); + drop(id.inner(), "files"); } void @@ -1014,7 +1019,7 @@ database::file_or_manifest_base_exists(h // just check for a delayed file, since there are no delayed manifests if (have_delayed_file(file_id(ident))) return true; - return table_has_entry(ident(), "id", table); + return table_has_entry(ident, "id", table); } // returns true if we are currently storing (or planning to store) a @@ -1024,7 +1029,7 @@ database::roster_base_stored(revision_id { if (roster_cache.exists(ident) && roster_cache.is_dirty(ident)) return true; - return table_has_entry(ident.inner()(), "id", "rosters"); + return table_has_entry(ident.inner(), "id", "rosters"); } // returns true if we currently have a full-text for 'ident' available @@ -1036,24 +1041,25 @@ database::roster_base_available(revision { if (roster_cache.exists(ident)) return true; - return table_has_entry(ident.inner()(), "id", "rosters"); + return table_has_entry(ident.inner(), "id", "rosters"); } bool -database::delta_exists(string const & ident, +database::delta_exists(hexenc const & ident, string const & table) { return table_has_entry(ident, "id", table); } bool -database::delta_exists(string const & ident, - string const & base, +database::delta_exists(hexenc const & ident, + hexenc const & base, string const & table) { results res; query q("SELECT 1 FROM " + table + " WHERE id = ? and base = ? LIMIT 1"); - fetch(res, one_col, any_rows, q % text(ident) % text(base)); + fetch(res, one_col, any_rows, + q % blob(decode_hexenc(ident())) % blob(decode_hexenc(base()))); return !res.empty(); } @@ -1123,7 +1129,7 @@ database::get_ids(string const & table, for (size_t i = 0; i < res.size(); ++i) { - ids.insert(hexenc(res[i][0])); + ids.insert(hexenc(encode_hexenc(res[i][0]))); } } @@ -1143,7 +1149,7 @@ database::get_file_or_manifest_base_unch results res; query q("SELECT data FROM " + table + " WHERE id = ?"); - fetch(res, one_col, one_row, q % text(ident())); + fetch(res, one_col, one_row, q % blob(decode_hexenc(ident()))); gzip rdata(res[0][0]); data rdata_unpacked; @@ -1163,17 +1169,17 @@ database::get_file_or_manifest_delta_unc I(base() != ""); results res; query q("SELECT delta FROM " + table + " WHERE id = ? AND base = ?"); - fetch(res, one_col, one_row, q % text(ident()) % text(base())); + fetch(res, one_col, one_row, + q % blob(decode_hexenc(ident())) % blob(decode_hexenc(base()))); gzip del_packed(res[0][0]); decode_gzip(del_packed, del); } void -database::get_roster_base(string const & ident_str, +database::get_roster_base(revision_id const & ident, roster_t & roster, marking_map & marking) { - revision_id ident(ident_str); if (roster_cache.exists(ident)) { cached_roster cr; @@ -1186,7 +1192,7 @@ database::get_roster_base(string const & } results res; query q("SELECT checksum, data FROM rosters WHERE id = ?"); - fetch(res, 2, one_row, q % text(ident_str)); + fetch(res, 2, one_row, q % blob(decode_hexenc(ident.inner()()))); hexenc checksum(res[0][0]); hexenc calculated; @@ -1200,13 +1206,13 @@ void } void -database::get_roster_delta(string const & ident, - string const & base, +database::get_roster_delta(hexenc const & ident, + hexenc const & base, roster & del) { results res; query q("SELECT checksum, delta FROM roster_deltas WHERE id = ? AND base = ?"); - fetch(res, 2, one_row, q % text(ident) % text(base)); + fetch(res, 2, one_row, q % blob(decode_hexenc(ident())) % blob(decode_hexenc(base()))); hexenc checksum(res[0][0]); hexenc calculated; @@ -1235,7 +1241,7 @@ database::write_delayed_file(file_id con I(tid == ident); // and then write things to the db query q("INSERT INTO files (id, data) VALUES (?, ?)"); - execute(q % text(ident.inner()()) % blob(dat_packed())); + execute(q % blob(decode_hexenc(ident.inner()())) % blob(dat_packed())); } void @@ -1255,7 +1261,7 @@ database::write_delayed_roster(revision_ // and then write it query q("INSERT INTO rosters (id, checksum, data) VALUES (?, ?, ?)"); - execute(q % text(ident.inner()()) % text(checksum()) % blob(dat_packed())); + execute(q % blob(decode_hexenc(ident.inner()())) % text(checksum()) % blob(dat_packed())); } @@ -1273,8 +1279,8 @@ database::put_file_delta(file_id const & query q("INSERT INTO file_deltas VALUES (?, ?, ?)"); execute(q - % text(ident.inner()()) - % text(base.inner()()) + % blob(decode_hexenc(ident.inner()())) + % blob(decode_hexenc(base.inner()())) % blob(del_packed())); } @@ -1291,8 +1297,8 @@ database::put_roster_delta(revision_id c query q("INSERT INTO roster_deltas (id, base, checksum, delta) VALUES (?, ?, ?, ?)"); execute(q - % text(ident.inner()()) - % text(base.inner()()) + % blob(decode_hexenc(ident.inner()())) + % blob(decode_hexenc(base.inner()())) % text(checksum()) % blob(del_packed())); } @@ -1319,19 +1325,19 @@ struct file_and_manifest_reconstruction_ string const & delta_table) : db(db), data_table(data_table), delta_table(delta_table) {} - virtual bool is_base(std::string const & node) const + virtual bool is_base(hexenc const & node) const { - return vcache.exists(node) - || db.file_or_manifest_base_exists(hexenc(node), data_table); + return vcache.exists(node()) + || db.file_or_manifest_base_exists(node, data_table); } - virtual void get_next(std::string const & from, std::set & next) const + virtual void get_next(hexenc const & from, std::set< hexenc > & next) const { next.clear(); database::results res; query q("SELECT base FROM " + delta_table + " WHERE id = ?"); - db.fetch(res, one_col, any_rows, q % text(from)); + db.fetch(res, one_col, any_rows, q % blob(decode_hexenc(from()))); for (database::results::const_iterator i = res.begin(); i != res.end(); ++i) - next.insert((*i)[0]); + next.insert(hexenc(encode_hexenc((*i)[0]))); } }; @@ -1347,7 +1353,7 @@ database::get_version(hexenc const & reconstruction_path selected_path; { file_and_manifest_reconstruction_graph graph(*this, data_table, delta_table); - get_reconstruction_path(ident(), graph, selected_path); + get_reconstruction_path(ident, graph, selected_path); } I(!selected_path.empty()); @@ -1401,18 +1407,18 @@ struct roster_reconstruction_graph : pub { database & db; roster_reconstruction_graph(database & db) : db(db) {} - virtual bool is_base(std::string const & node) const + virtual bool is_base(hexenc const & node) const { return db.roster_base_available(revision_id(node)); } - virtual void get_next(std::string const & from, std::set & next) const + virtual void get_next(hexenc const & from, std::set< hexenc > & next) const { next.clear(); database::results res; query q("SELECT base FROM roster_deltas WHERE id = ?"); - db.fetch(res, one_col, any_rows, q % text(from)); + db.fetch(res, one_col, any_rows, q % blob(decode_hexenc(from()))); for (database::results::const_iterator i = res.begin(); i != res.end(); ++i) - next.insert((*i)[0]); + next.insert(hexenc(encode_hexenc((*i)[0]))); } }; @@ -1472,7 +1478,7 @@ void }; void -database::extract_from_deltas(revision_id const & id, extractor & x) +database::extract_from_deltas(revision_id const & ident, extractor & x) { reconstruction_path selected_path; { @@ -1489,24 +1495,24 @@ database::extract_from_deltas(revision_i // recording the deltas visited here in a set as to avoid inspecting // them later seems to be of little value, as it imposes a cost here, // but can seldom be exploited. - set deltas; - graph.get_next(id.inner()(), deltas); - for (set::const_iterator i = deltas.begin(); + set< hexenc > deltas; + graph.get_next(ident.inner(), deltas); + for (set< hexenc >::const_iterator i = deltas.begin(); i != deltas.end(); ++i) { roster_delta del; - get_roster_delta(id.inner()(), *i, del); + get_roster_delta(ident.inner(), *i, del); bool found = x.look_at_delta(del); if (found) return; } } - get_reconstruction_path(id.inner()(), graph, selected_path); + get_reconstruction_path(ident.inner(), graph, selected_path); } int path_length(selected_path.size()); int i(0); - string target_rev; + hexenc target_rev; for (reconstruction_path::const_iterator p = selected_path.begin(); p != selected_path.end(); ++p) @@ -1524,7 +1530,7 @@ database::extract_from_deltas(revision_i // last iteration, we have reached a roster base roster_t roster; marking_map mm; - get_roster_base(*p, roster, mm); + get_roster_base(revision_id(*p), roster, mm); x.look_at_roster(roster, mm); return; } @@ -1558,34 +1564,34 @@ void } void -database::get_roster_version(revision_id const & id, +database::get_roster_version(revision_id const & ros_id, cached_roster & cr) { // if we already have it, exit early - if (roster_cache.exists(id)) + if (roster_cache.exists(ros_id)) { - roster_cache.fetch(id, cr); + roster_cache.fetch(ros_id, cr); return; } reconstruction_path selected_path; { roster_reconstruction_graph graph(*this); - get_reconstruction_path(id.inner()(), graph, selected_path); + get_reconstruction_path(ros_id.inner(), graph, selected_path); } - string curr = selected_path.back(); + hexenc curr = selected_path.back(); selected_path.pop_back(); // we know that this isn't already in the cache (because of the early exit // above), so we should create new objects and spend time filling them in. shared_ptr roster(new roster_t); shared_ptr marking(new marking_map); - get_roster_base(curr, *roster, *marking); + get_roster_base(revision_id(curr), *roster, *marking); for (reconstruction_path::reverse_iterator i = selected_path.rbegin(); i != selected_path.rend(); ++i) { - string const nxt = *i; + hexenc const nxt = *i; L(FL("following delta %s -> %s") % curr % nxt); roster_delta del; get_roster_delta(nxt, curr, del); @@ -1605,23 +1611,23 @@ database::get_roster_version(revision_id // this is the only thing that can catch it. roster->check_sane_against(*marking); manifest_id expected_mid, actual_mid; - get_revision_manifest(id, expected_mid); + get_revision_manifest(ros_id, expected_mid); calculate_ident(*roster, actual_mid); I(expected_mid == actual_mid); // const'ify the objects, to save them and pass them out cr.first = roster; cr.second = marking; - roster_cache.insert_clean(id, cr); + roster_cache.insert_clean(ros_id, cr); } void -database::drop(string const & ident, +database::drop(hexenc const & ident, string const & table) { string drop = "DELETE FROM " + table + " WHERE id = ?"; - execute(query(drop) % text(ident)); + execute(query(drop) % blob(decode_hexenc(ident()))); } // ------------------------------------------------------------ @@ -1633,14 +1639,14 @@ database::file_version_exists(file_id co bool database::file_version_exists(file_id const & id) { - return delta_exists(id.inner()(), "file_deltas") + return delta_exists(id.inner(), "file_deltas") || file_or_manifest_base_exists(id.inner(), "files"); } bool database::roster_version_exists(revision_id const & id) { - return delta_exists(id.inner()(), "roster_deltas") + return delta_exists(id.inner(), "roster_deltas") || roster_base_available(id); } @@ -1649,7 +1655,7 @@ database::revision_exists(revision_id co { results res; query q("SELECT id FROM revisions WHERE id = ?"); - fetch(res, one_col, any_rows, q % text(id.inner()())); + fetch(res, one_col, any_rows, q % blob(decode_hexenc(id.inner()()))); I(res.size() <= 1); return res.size() == 1; } @@ -1757,10 +1763,10 @@ database::put_file_version(file_id const if (!file_or_manifest_base_exists(new_id.inner(), "files")) { schedule_delayed_file(new_id, new_data); - drop(new_id.inner()(), "file_deltas"); + drop(new_id.inner(), "file_deltas"); } - if (!delta_exists(old_id.inner()(), new_id.inner()(), "file_deltas")) + if (!delta_exists(old_id.inner(), new_id.inner(), "file_deltas")) { put_file_delta(old_id, new_id, reverse_delta); guard.commit(); @@ -1828,8 +1834,8 @@ database::get_revision_ancestry(rev_ance fetch(res, 2, any_rows, query("SELECT parent,child FROM revision_ancestry")); for (size_t i = 0; i < res.size(); ++i) - graph.insert(make_pair(revision_id(res[i][0]), - revision_id(res[i][1]))); + graph.insert(make_pair(revision_id(encode_hexenc(res[i][0])), + revision_id(encode_hexenc(res[i][1])))); } void @@ -1841,9 +1847,9 @@ database::get_revision_parents(revision_ parents.clear(); fetch(res, one_col, any_rows, query("SELECT parent FROM revision_ancestry WHERE child = ?") - % text(id.inner()())); + % blob(decode_hexenc(id.inner()()))); for (size_t i = 0; i < res.size(); ++i) - parents.insert(revision_id(res[i][0])); + parents.insert(revision_id(encode_hexenc(res[i][0]))); } void @@ -1854,9 +1860,9 @@ database::get_revision_children(revision children.clear(); fetch(res, one_col, any_rows, query("SELECT child FROM revision_ancestry WHERE parent = ?") - % text(id.inner()())); + % blob(decode_hexenc(id.inner()()))); for (size_t i = 0; i < res.size(); ++i) - children.insert(revision_id(res[i][0])); + children.insert(revision_id(encode_hexenc(res[i][0]))); } void @@ -1885,7 +1891,7 @@ database::get_revision(revision_id const results res; fetch(res, one_col, one_row, query("SELECT data FROM revisions WHERE id = ?") - % text(id.inner()())); + % blob(decode_hexenc(id.inner()()))); gzip gzdata(res[0][0]); data rdat; @@ -1920,7 +1926,7 @@ database::get_rev_height(revision_id con results res; fetch(res, one_col, one_row, query("SELECT height FROM heights WHERE revision = ?") - % text(id.inner()())); + % blob(decode_hexenc(id.inner()()))); I(res.size() == 1); @@ -1946,7 +1952,7 @@ database::put_rev_height(revision_id con height_cache.erase(id); execute(query("INSERT INTO heights VALUES(?, ?)") - % text(id.inner()()) + % blob(decode_hexenc(id.inner()())) % blob(height())); } @@ -1990,7 +1996,7 @@ database::deltify_revision(revision_id c diff(old_data.inner(), new_data.inner(), delt); file_delta del(delt); drop_or_cancel_file(delta_entry_dst(j)); - drop(delta_entry_dst(j).inner()(), "file_deltas"); + drop(delta_entry_dst(j).inner(), "file_deltas"); put_file_version(delta_entry_src(j), delta_entry_dst(j), del); } } @@ -2077,15 +2083,15 @@ database::put_revision(revision_id const gzip d_packed; encode_gzip(d.inner(), d_packed); execute(query("INSERT INTO revisions VALUES(?, ?)") - % text(new_id.inner()()) + % blob(decode_hexenc(new_id.inner()())) % blob(d_packed())); for (edge_map::const_iterator e = rev.edges.begin(); e != rev.edges.end(); ++e) { execute(query("INSERT INTO revision_ancestry VALUES(?, ?)") - % text(edge_old_revision(e).inner()()) - % text(new_id.inner()())); + % blob(decode_hexenc(edge_old_revision(e).inner()())) + % blob(decode_hexenc(new_id.inner()()))); } // Phase 3: Construct and write the roster (which also checks the manifest @@ -2228,17 +2234,17 @@ database::delete_existing_rev_and_certs( // Kill the certs, ancestry, and revision. execute(query("DELETE from revision_certs WHERE id = ?") - % text(rid.inner()())); + % blob(decode_hexenc(rid.inner()()))); cert_stamper.note_change(); execute(query("DELETE from revision_ancestry WHERE child = ?") - % text(rid.inner()())); + % blob(decode_hexenc(rid.inner()()))); execute(query("DELETE from heights WHERE revision = ?") - % text(rid.inner()())); + % blob(decode_hexenc(rid.inner()()))); execute(query("DELETE from revisions WHERE id = ?") - % text(rid.inner()())); + % blob(decode_hexenc(rid.inner()()))); guard.commit(); } @@ -2412,7 +2418,7 @@ database::cert_exists(cert const & t, "AND value = ? " "AND keypair = ? " "AND signature = ?") - % text(t.ident()) + % text(decode_hexenc(t.ident())) % text(t.name()) % blob(value()) % text(t.key()) @@ -2438,8 +2444,8 @@ database::put_cert(cert const & t, string insert = "INSERT INTO " + table + " VALUES(?, ?, ?, ?, ?, ?)"; execute(query(insert) - % text(thash()) - % text(t.ident()) + % blob(decode_hexenc(thash())) + % blob(decode_hexenc(t.ident())) % text(t.name()) % blob(value()) % text(t.key()) @@ -2458,7 +2464,7 @@ database::results_to_certs(results const encode_base64(cert_value(res[i][2]), value); base64 sig; encode_base64(rsa_sha1_signature(res[i][4]), sig); - t = cert(hexenc(res[i][0]), + t = cert(hexenc(encode_hexenc(res[i][0])), cert_name(res[i][1]), value, rsa_keypair_id(res[i][3]), @@ -2497,7 +2503,7 @@ database::get_certs(hexenc const & i query q("SELECT id, name, value, keypair, signature FROM " + table + " WHERE id = ?"); - fetch(res, 5, any_rows, q % text(ident())); + fetch(res, 5, any_rows, q % blob(decode_hexenc(ident()))); results_to_certs(res, certs); } @@ -2526,7 +2532,7 @@ database::get_certs(hexenc const & i " WHERE id = ? AND name = ?"); fetch(res, 5, any_rows, - q % text(ident()) + q % blob(decode_hexenc(ident())) % text(name())); results_to_certs(res, certs); } @@ -2564,7 +2570,7 @@ database::get_certs(hexenc const & i cert_value binvalue; decode_base64(value, binvalue); fetch(res, 5, any_rows, - q % text(ident()) + q % blob(decode_hexenc(ident())) % text(name()) % blob(binvalue())); results_to_certs(res, certs); @@ -2617,8 +2623,8 @@ database::get_revision_cert_nobranch_ind idx.reserve(res.size()); for (results::const_iterator i = res.begin(); i != res.end(); ++i) { - idx.push_back(make_pair(hexenc((*i)[0]), - make_pair(revision_id((*i)[1]), + idx.push_back(make_pair(hexenc(encode_hexenc((*i)[0])), + make_pair(revision_id(encode_hexenc((*i)[1])), rsa_keypair_id((*i)[2])))); } return cert_stamper.get_indicator(); @@ -2682,7 +2688,7 @@ database::get_revisions_with_cert(cert_n decode_base64(val, binvalue); fetch(res, one_col, any_rows, q % text(name()) % blob(binvalue())); for (results::const_iterator i = res.begin(); i != res.end(); ++i) - revisions.insert(revision_id((*i)[0])); + revisions.insert(revision_id(encode_hexenc((*i)[0]))); return cert_stamper.get_indicator(); } @@ -2719,7 +2725,7 @@ database::get_revision_certs(revision_id query("SELECT hash " "FROM revision_certs " "WHERE id = ?") - % text(ident.inner()())); + % blob(decode_hexenc(ident.inner()()))); ts.clear(); for (size_t i = 0; i < res.size(); ++i) ts.push_back(hexenc(res[i][0])); @@ -2736,7 +2742,7 @@ database::get_revision_cert(hexenc c query("SELECT id, name, value, keypair, signature " "FROM revision_certs " "WHERE hash = ?") - % text(hash())); + % blob(decode_hexenc(hash()))); results_to_certs(res, certs); I(certs.size() == 1); c = revision(certs[0]); @@ -2751,7 +2757,7 @@ database::revision_cert_exists(hexenc const & key, std::string const & column, std::string const & table); // @@ -213,11 +213,11 @@ private: bool roster_base_available(revision_id const & ident); // "do we have any entry for 'ident' that is a delta" - bool delta_exists(std::string const & ident, + bool delta_exists(hexenc const & ident, std::string const & table); - bool delta_exists(std::string const & ident, - std::string const & base, + bool delta_exists(hexenc const & ident, + hexenc const & base, std::string const & table); void get_file_or_manifest_base_unchecked(hexenc const & new_id, @@ -227,10 +227,10 @@ private: hexenc const & base, delta & del, std::string const & table); - void get_roster_base(std::string const & ident, + void get_roster_base(revision_id const & ident, roster_t & roster, marking_map & marking); - void get_roster_delta(std::string const & ident, - std::string const & base, + void get_roster_delta(hexenc const & ident, + hexenc const & base, roster_delta & del); friend struct file_and_manifest_reconstruction_graph; friend struct roster_reconstruction_graph; @@ -239,7 +239,7 @@ private: std::string const & data_table, std::string const & delta_table); - void drop(std::string const & base, + void drop(hexenc const & base, std::string const & table); void put_file_delta(file_id const & ident, file_id const & base, @@ -364,7 +364,7 @@ private: struct extractor; struct file_content_extractor; struct markings_extractor; - void extract_from_deltas(revision_id const & id, extractor & x); + void extract_from_deltas(revision_id const & ident, extractor & x); // // --== Keys ==-- ============================================================ --- graph.cc 2d934cb225b5639919fec3eda0cbec615cf2f903 +++ graph.cc fc6bcec20a325cc94d936a718437558e0489078d @@ -24,7 +24,7 @@ void using hashmap::hash_set; void -get_reconstruction_path(std::string const & start, +get_reconstruction_path(hexenc const & start, reconstruction_graph const & graph, reconstruction_path & path) { @@ -61,7 +61,7 @@ get_reconstruction_path(std::string cons } shared_ptr selected_path; - set seen_nodes; + set< hexenc > seen_nodes; while (!selected_path) { @@ -72,7 +72,7 @@ get_reconstruction_path(std::string cons i != live_paths.end(); ++i) { shared_ptr pth = *i; - string tip = pth->back(); + hexenc tip = pth->back(); if (graph.is_base(tip)) { @@ -82,13 +82,14 @@ get_reconstruction_path(std::string cons else { // This tip is not a root, so extend the path. - set next; + set< hexenc > next; graph.get_next(tip, next); I(!next.empty()); // Replicate the path if there's a fork. bool first = true; - for (set::const_iterator j = next.begin(); j != next.end(); ++j) + for (set< hexenc >::const_iterator j = next.begin(); + j != next.end(); ++j) { L(FL("considering %s -> %s") % tip % *j); if (seen_nodes.find(*j) == seen_nodes.end()) @@ -137,24 +138,25 @@ get_reconstruction_path(std::string cons #include "unit_tests.hh" #include "randomizer.hh" +#include "transforms.hh" #include "lexical_cast.hh" using boost::lexical_cast; using std::pair; -typedef std::multimap rg_map; +typedef std::multimap< hexenc, hexenc > rg_map; struct mock_reconstruction_graph : public reconstruction_graph { rg_map ancestry; - set bases; - mock_reconstruction_graph(rg_map const & ancestry, set const & bases) + set< hexenc > bases; + mock_reconstruction_graph(rg_map const & ancestry, set< hexenc > const & bases) : ancestry(ancestry), bases(bases) {} - virtual bool is_base(string const & node) const + virtual bool is_base(hexenc const & node) const { return bases.find(node) != bases.end(); } - virtual void get_next(string const & from, set & next) const + virtual void get_next(hexenc const & from, set< hexenc > & next) const { typedef rg_map::const_iterator ci; pair range = ancestry.equal_range(from); @@ -166,12 +168,12 @@ make_random_reconstruction_graph(size_t static void make_random_reconstruction_graph(size_t num_nodes, size_t num_random_edges, size_t num_random_bases, - vector & all_nodes, rg_map & ancestry, - set & bases, + vector< hexenc > & all_nodes, rg_map & ancestry, + set< hexenc > & bases, randomizer & rng) { for (size_t i = 0; i != num_nodes; ++i) - all_nodes.push_back(lexical_cast(i)); + all_nodes.push_back(hexenc(lexical_cast(i))); // We put a single long chain of edges in, to make sure that everything is // reconstructable somehow. for (size_t i = 1; i != num_nodes; ++i) @@ -193,7 +195,7 @@ static void } static void -check_reconstruction_path(string const & start, reconstruction_graph const & graph, +check_reconstruction_path(hexenc const & start, reconstruction_graph const & graph, reconstruction_path const & path) { I(!path.empty()); @@ -203,7 +205,7 @@ check_reconstruction_path(string const & I(graph.is_base(*last)); for (reconstruction_path::const_iterator i = path.begin(); i != last; ++i) { - set children; + set< hexenc > children; graph.get_next(*i, children); reconstruction_path::const_iterator next = i; ++next; @@ -217,14 +219,14 @@ run_get_reconstruction_path_tests_on_ran size_t num_random_bases, randomizer & rng) { - vector all_nodes; + vector< hexenc > all_nodes; rg_map ancestry; - set bases; + set< hexenc > bases; make_random_reconstruction_graph(num_nodes, num_random_edges, num_random_bases, all_nodes, ancestry, bases, rng); mock_reconstruction_graph graph(ancestry, bases); - for (vector::const_iterator i = all_nodes.begin(); + for (vector< hexenc >::const_iterator i = all_nodes.begin(); i != all_nodes.end(); ++i) { reconstruction_path path; ============================================================ --- graph.hh 6384f6bd01b8b43383ba2e6adf6ae10b6f725bac +++ graph.hh a463fb39255436e51b39d02c3488bd2e349a0fdc @@ -26,15 +26,15 @@ struct reconstruction_graph struct reconstruction_graph { - virtual bool is_base(std::string const & node) const = 0; - virtual void get_next(std::string const & from, std::set & next) const = 0; + virtual bool is_base(hexenc const & node) const = 0; + virtual void get_next(hexenc const & from, std::set< hexenc > & next) const = 0; virtual ~reconstruction_graph() {}; }; -typedef std::vector reconstruction_path; +typedef std::vector< hexenc > reconstruction_path; void -get_reconstruction_path(std::string const & start, +get_reconstruction_path(hexenc const & start, reconstruction_graph const & graph, reconstruction_path & path); ============================================================ --- rcs_import.cc f6ce4f02b7f5e254f6be4e5e98739fce77b62947 +++ rcs_import.cc 5a6ffafdc0f791e90bc5cd2627e9262210731358 @@ -471,7 +471,7 @@ rcs_put_raw_file_edge(hexenc const & else { I(db.file_or_manifest_base_exists(new_id, "files") - || db.delta_exists(new_id(), "file_deltas")); + || db.delta_exists(new_id, "file_deltas")); db.put_file_delta(file_id(old_id), file_id(new_id), file_delta(del)); } } ============================================================ --- schema.sql c093f206468fcc6663167a57258c07adb9c33880 +++ schema.sql 8102b2a148c8c9220db03d8cd79ffb89ccd549c6 @@ -106,7 +106,7 @@ CREATE TABLE branch_epochs ( hash not null unique, -- hash of remaining fields separated by ":" branch not null unique, -- joins with revision_certs.value - epoch not null -- random hex-encoded id + epoch not null -- random binary id ); -- database-local variables used to manage various things ============================================================ --- schema_migration.cc 769321d3bb854322d9de25354e9e240396cf1096 +++ schema_migration.cc 49bd56dbd04ea1bd9156aac3c7642af398db4064 @@ -302,6 +302,28 @@ sqlite3_unbase64_fn(sqlite3_context *f, sqlite3_result_blob(f, decoded().c_str(), decoded().size(), SQLITE_TRANSIENT); } +static void +sqlite3_unhex_fn(sqlite3_context *f, int nargs, sqlite3_value **args) +{ + if (nargs != 1) + { + sqlite3_result_error(f, "need exactly 1 arg to unhex()", -1); + return; + } + data decoded; + + try + { + decode_hexenc(hexenc(string(sqlite3_value_cstr(args[0]))), decoded); + } + catch (informative_failure & e) + { + sqlite3_result_error(f, e.what(), -1); + return; + } + sqlite3_result_blob(f, decoded().c_str(), decoded().size(), SQLITE_TRANSIENT); +} + // Here are all of the migration steps. Almost all of them can be expressed // entirely as a series of SQL statements; those statements are packaged // into a long, continued string constant for the step. One step requires a @@ -615,6 +637,28 @@ char const migrate_add_heights_index[] = "CREATE INDEX heights__height ON heights (height);" ; +char const migrate_to_binary_hashes[] = + "UPDATE files SET id=unhex(id);" + "UPDATE file_deltas SET id=unhex(id), base=unhex(base);" + "UPDATE revisions SET id=unhex(id);" + "UPDATE revision_ancestry SET parent=unhex(parent), child=unhex(child);" + "UPDATE heights SET revision=unhex(revision);" + "UPDATE rosters SET id=unhex(id);" + "UPDATE roster_deltas SET id=unhex(id), base=unhex(base);" + "UPDATE public_keys SET hash=unhex(hash);" + "UPDATE revision_certs SET hash=unhex(hash), id=unhex(id);" + + // we altered a comment on this table, thus we need to recreated it + "ALTER TABLE branch_epochs RENAME TO tmp;" + "CREATE TABLE branch_epochs" + " ( hash not null unique, -- hash of remaining fields separated by \":\"\n" + " branch not null unique, -- joins with revision_certs.value\n" + " epoch not null -- random binary id\n" + " );" + "INSERT INTO branch_epochs SELECT unhex(hash), branch, unhex(epoch) FROM tmp;" + "DROP TABLE tmp;" + ; + // this is a function because it has to refer to the numeric constant // defined in schema_migration.hh. static void @@ -704,9 +748,12 @@ const migration_event migration_events[] { "fe48b0804e0048b87b4cea51b3ab338ba187bdc2", migrate_add_heights_index, 0, upgrade_none }, + { "7ca81b45279403419581d7fde31ed888a80bd34e", + migrate_to_binary_hashes, 0, upgrade_none }, + // The last entry in this table should always be the current // schema ID, with 0 for the migrators. - { "7ca81b45279403419581d7fde31ed888a80bd34e", 0, 0, upgrade_none } + { "1cc9d0ca03a545790b6e29ea7b7b534e8c3458a1", 0, 0, upgrade_none } }; const size_t n_migration_events = (sizeof migration_events / sizeof migration_events[0]); @@ -960,6 +1007,7 @@ migrate_sql_schema(sqlite3 * db, app_sta sql::create_function(db, "sha1", sqlite_sha1_fn); sql::create_function(db, "unbase64", sqlite3_unbase64_fn); + sql::create_function(db, "unhex", sqlite3_unhex_fn); P(F("migrating data..."));