# # patch "database.cc" # from [4ee08f7847908cc5b369a804a246bffdbf7aaa7e] # to [b38cff6e9f0d3727afb7a3fc6113d4d959929790] # # patch "database.hh" # from [ac1453913dc16dddd51e9320d8f29870030d5ac5] # to [72206f8334e585a3866b88bc251c496f131d3515] # # patch "roster4.hh" # from [cdc53ad3a448e8b3794f90468d8e9d944910f847] # to [8b007fd8271c97603857b53ff95f3aa4f8834ff4] # # patch "schema.sql" # from [ac99524347304a61fe2d857bc45d1bcca73adb6e] # to [62dc6c62cf12db05829c9dac9713eb1dcdec9986] # ======================================================================== --- database.cc 4ee08f7847908cc5b369a804a246bffdbf7aaa7e +++ database.cc b38cff6e9f0d3727afb7a3fc6113d4d959929790 @@ -2438,7 +2438,7 @@ results res; string query="SELECT DISTINCT value FROM revision_certs WHERE name= ?"; string cert_name="branch"; - fetch(res,one_col,any_rows,query.c_str(),cert_name.c_str()); + fetch(res, one_col, any_rows, query.c_str(), cert_name.c_str()); for (size_t i = 0; i < res.size(); ++i) { base64 row_encoded(res[i][0]); @@ -2448,16 +2448,110 @@ } } + +void +database::get_roster_id_for_revision(revision_id const & rev_id, + hexenc & roster_id) +{ + results res; + string data_table = "rosters"; + string delta_table = "roster_deltas"; + string query = ("SELECT id FROM " + data_table + " WHERE rev_id = ? " + "UNION " + "SELECT id FROM " + delta_table + " WHERE rev_id = ? "); + + fetch(res, one_col, one_row, query.c_str(), + rev_id.inner()().c_str(), + rev_id.inner()().c_str()); + roster_id = hexenc(res[0][0]); +} + + void -database::get_roster(revision_id const & rid, +database::get_roster(revision_id const & rev_id, roster_t & roster, marking_map & marks) { - // FIXME: implement - I(false); + string data_table = "rosters"; + string delta_table = "roster_deltas"; + data dat; + hexenc ident; + + get_roster_id_for_revision(rev_id, ident); + get_version(ident, dat, data_table, delta_table); + read_roster_and_marking(dat, roster, marks); } +void +database::put_roster(revision_id const & rev_id, + roster_t & roster, + marking_map & marks) +{ + data old_data, new_data; + delta reverse_delta; + hexenc ident; + base64 > new_data_packed; + + write_roster_and_marking(roster, marks, new_data, true); + calculate_ident(new_data, ident); + pack(new_data, new_data_packed); + + // First: find the "old" revision; if there are multiple old + // revisions, we just pick the first. It probably doesn't matter for + // the sake of delta-encoding. + + string data_table = "rosters"; + string delta_table = "roster_deltas"; + + results res; + fetch(res, one_col, any_rows, + "SELECT parent FROM revision_ancestry WHERE child = ?", + rev_id.inner()().c_str()); + + transaction_guard guard(*this); + if (res.size() != 0) + { + // There's a parent revision; we are going to do delta + // compression on the roster by using the roster associated with + // the parent rev. Keep in mind that we're composing a *reverse* + // delta here, which goes from new->old. So the row we insert + // will have (id=old_id, rev_id=old_rev, base=new_id, + // delta=new->old) + + revision_id old_rev = revision_id(res[0][0]); + hexenc old_ident; + get_roster_id_for_revision(old_rev, old_ident); + get_version(old_ident, old_data, data_table, delta_table); + diff(new_data, old_data, reverse_delta); + base64 > del_packed; + pack(reverse_delta, del_packed); + + if (exists(old_ident, data_table)) + { + // Descendent of a head version replaces the head, therefore + // old head, if it exists in entirety, must be disposed of. + drop(old_ident, data_table); + } + + // nb: roster_deltas schema is (id, rev_id, base, delta) + string query = "INSERT INTO " + delta_table + " VALUES(?, ?, ?, ?)"; + execute(query.c_str(), + old_ident().c_str(), old_rev.inner()().c_str(), + ident().c_str(), del_packed().c_str()); + + } + + // nb: rosters schema is (id, rev_id, data) + string query = "INSERT INTO " + data_table + " VALUES(?, ?, ?, ?)"; + execute(query.c_str(), + ident().c_str(), rev_id.inner()().c_str(), + new_data_packed().c_str()); + + guard.commit(); +} + + typedef hashmap::hash_multimap ancestry_map; static void ======================================================================== --- database.hh ac1453913dc16dddd51e9320d8f29870030d5ac5 +++ database.hh 72206f8334e585a3866b88bc251c496f131d3515 @@ -435,9 +435,17 @@ // roster and node_id stuff + void get_roster_id_for_revision(revision_id const & rev_id, + hexenc & roster_id); + + void put_roster(revision_id const & rev_id, + roster_t & roster, + marking_map & marks); + void get_roster(revision_id const & rid, roster_t & roster, marking_map & marks); + void get_uncommon_ancestors(revision_id const & a, revision_id const & b, std::set & a_uncommon_ancs, ======================================================================== --- roster4.hh cdc53ad3a448e8b3794f90468d8e9d944910f847 +++ roster4.hh 8b007fd8271c97603857b53ff95f3aa4f8834ff4 @@ -237,5 +237,16 @@ marking_map & marking, app_state & app); +void +read_roster_and_marking(data const & dat, + roster_t & ros, + marking_map & mm); + +void +write_roster_and_marking(roster_t const & ros, + marking_map const & mm, + data & dat, + bool print_local_parts); + #endif ======================================================================== --- schema.sql ac99524347304a61fe2d857bc45d1bcca73adb6e +++ schema.sql 62dc6c62cf12db05829c9dac9713eb1dcdec9986 @@ -58,6 +58,24 @@ unique(parent, child) ); +CREATE TABLE rosters + ( + id primary key, -- strong hash of the roster + rev_id not null unique, -- strong hash of associated revision + data not null -- compressed, encoded contents of the roster + ); + +CREATE TABLE roster_deltas + ( + id not null, -- strong hash of the roster + rev_id not null, -- strong hash of associated revision + base not null, -- joins with either rosters.id or roster_deltas.id + delta not null, -- rdiff to construct current from base + unique(id, base), + unique(rev_id, base) + ); + + CREATE INDEX revision_ancestry__child ON revision_ancestry (child); -- structures for managing RSA keys and file / manifest certs