The unified diff between revisions [2449c78b..] and [ebdccab0..] is displayed below. It can also be downloaded as a raw diff.

This diff has been restricted to the following files: 'database.cc'

#
#
# patch "database.cc"
#  from [1cd429afd5808a6b11ca51f037108d31f290873a]
#    to [fd5eff861239cd1408cca007c0df653f8a0f7d3f]
#
============================================================
--- database.cc	1cd429afd5808a6b11ca51f037108d31f290873a
+++ database.cc	fd5eff861239cd1408cca007c0df653f8a0f7d3f
@@ -794,6 +794,17 @@ database::delta_exists(hexenc<id> const
   return res.size() > 0;
 }

+bool
+database::delta_exists(hexenc<id> const & ident,
+                       hexenc<id> const & base,
+                       string const & table)
+{
+  results res;
+  query q("SELECT id FROM " + table + " WHERE id = ? AND base = ?");
+  fetch(res, one_col, any_rows, q % text(ident()) % text(base()));
+  return res.size() > 0;
+}
+
 unsigned long
 database::count(string const & table)
 {
@@ -1170,23 +1181,10 @@ database::put_version(hexenc<id> const &
                       string const & data_table,
                       string const & delta_table)
 {
+  // TODO: add an invariant or something perhaps

-  data old_data, new_data;
-  delta reverse_delta;
-
-  get_version(old_id, old_data, data_table, delta_table);
-  patch(old_data, del, new_data);
-  diff(new_data, old_data, reverse_delta);
-
   transaction_guard guard(*this);
-  if (exists(old_id, data_table))
-    {
-      // descendent of a head version replaces the head, therefore old head
-      // must be disposed of
-      drop(old_id, data_table);
-    }
-  put(new_id, new_data, data_table);
-  put_delta(old_id, new_id, reverse_delta, delta_table);
+  put_delta(new_id, old_id, del, delta_table);
   guard.commit();
 }

@@ -1376,6 +1374,29 @@ database::get_file_version(file_id const
   dat = tmp;
 }

+void
+database::get_file_delta(file_id const & id,
+                         file_id const & base,
+                         file_delta & del)
+{
+  if (delta_exists(id.inner(), base.inner(), "file_deltas"))
+    {
+      delta d;
+      get_delta(id.inner(), base.inner(), d, "file_deltas");
+      del = file_delta(d);
+    }
+  else
+    {
+      L(FL("get_file_delta failed for '%s'->'%s'") % base % id);
+      file_data dat, base_dat;
+      get_file_version(base, base_dat);
+      get_file_version(id, dat);
+      delta d;
+      diff(base_dat.inner(), dat.inner(), d);
+      del = file_delta(d);
+    }
+}
+
 void
 database::get_manifest_version(manifest_id const & id,
                                manifest_data & dat)
@@ -1482,6 +1503,81 @@ database::get_revision(revision_id const
   dat = rdat;
 }

+void
+database::make_fwd_deltas(string const & data_table, string const & delta_table)
+{
+  transaction_guard guard(*this);
+
+  set< hexenc<id> > del_bases, all_ids;
+  set< pair< hexenc<id>, hexenc<id> > > dels;
+
+  // id, base
+  get_ids(data_table, all_ids);
+    {
+      results res;
+      fetch(res, 2, any_rows, query("SELECT id, base FROM " + delta_table));
+
+      for (size_t i = 0; i < res.size(); ++i)
+        {
+          all_ids.insert(hexenc<id>(res[i][0]));
+          del_bases.insert(hexenc<id>(res[i][1]));
+          dels.insert( make_pair(res[i][0], res[i][1]) );
+        }
+    }
+
+  set< hexenc<id> > new_bases;
+
+  set_difference(all_ids.begin(), all_ids.end(), del_bases.begin(), del_bases.end(),
+                 inserter(new_bases, new_bases.begin()));
+
+  // create some empty temporary tables
+  string tmp_data_table("tmp_" + data_table);
+  string tmp_delta_table("tmp_" + delta_table);
+
+  execute(query("CREATE TABLE " + tmp_data_table + " AS SELECT * FROM " + data_table + " WHERE 1=0"));
+  execute(query("CREATE TABLE " + tmp_delta_table + " AS SELECT * FROM " + delta_table + " WHERE 1=0"));
+
+  ticker full("full", "g", 1);
+  for ( set< hexenc<id> >::const_iterator i = new_bases.begin(); i != new_bases.end(); i++)
+    {
+      MM(*i);
+      data dat;
+      get_version(*i, dat, data_table, delta_table);
+      put(*i, dat, tmp_data_table);
+      ++full;
+    }
+
+  ticker flips("flips", "f", 1);
+
+  for ( set< pair< hexenc<id>, hexenc<id> > >::const_iterator i = dels.begin(); i != dels.end(); i++)
+    {
+      ++flips;
+      hexenc<id> new_id = i->second;
+      hexenc<id> new_base = i->first;
+      MM(new_id);
+      MM(new_base);
+
+      data base, dat;
+      get_version(new_id, dat, data_table, delta_table);
+      get_version(new_base, base, data_table, delta_table);
+      delta del;
+      diff(base, dat, del);
+
+      put_delta(new_id, new_base, del, tmp_delta_table);
+    }
+
+  execute(query("DELETE FROM " + data_table));
+  execute(query("DELETE FROM " + delta_table));
+
+  execute(query("INSERT INTO " + data_table + " SELECT * FROM " + tmp_data_table));
+  execute(query("INSERT INTO " + delta_table + " SELECT * FROM " + tmp_delta_table));
+
+  execute(query("DROP TABLE " + tmp_data_table));
+  execute(query("DROP TABLE " + tmp_delta_table));
+
+  guard.commit();
+}
+
 void
 database::deltify_revision(revision_id const & rid)
 {
@@ -1574,7 +1670,8 @@ database::put_revision(revision_id const
               % text(new_id.inner()()));
     }

-  deltify_revision(new_id);
+  // TODO: some different version?
+  // deltify_revision(new_id);

   // Phase 4: write the roster data and commit
   put_roster(new_id, ros, mm);
@@ -2639,7 +2736,6 @@ database::get_roster(revision_id const &
   read_roster_and_marking(dat, roster, marks);
 }

-
 void
 database::put_roster(revision_id const & rev_id,
                      roster_t & roster,
@@ -2647,7 +2743,6 @@ database::put_roster(revision_id const &
 {
   MM(rev_id);
   data old_data, new_data;
-  delta reverse_delta;
   hexenc<id> old_id, new_id;

   write_roster_and_marking(roster, marks, new_data);
@@ -2676,13 +2771,13 @@ database::put_roster(revision_id const &
   // Else we have a new roster the database hasn't seen yet; our task is to
   // add it, and deltify all the incoming edges (if they aren't already).

-  put(new_id, new_data, data_table);

   std::set<revision_id> parents;
   get_revision_parents(rev_id, parents);

   // Now do what deltify would do if we bothered (we have the
   // roster written now, so might as well do it here).
+  bool delta_written = false;
   for (std::set<revision_id>::const_iterator i = parents.begin();
        i != parents.end(); ++i)
     {
@@ -2690,14 +2785,18 @@ database::put_roster(revision_id const &
         continue;
       revision_id old_rev = *i;
       get_roster_id_for_revision(old_rev, old_id);
-      if (exists(new_id, data_table))
-        {
-          get_version(old_id, old_data, data_table, delta_table);
-          diff(new_data, old_data, reverse_delta);
-          drop(old_id, data_table);
-          put_delta(old_id, new_id, reverse_delta, delta_table);
-        }
+      get_version(old_id, old_data, data_table, delta_table);
+      delta del;
+      diff(old_data, new_data, del);
+      put_delta(new_id, old_id, del, delta_table);
+      delta_written = true;
+      break;
     }
+
+  // in case the parents were all null/didn't exist
+  if (!delta_written)
+    put(new_id, new_data, data_table);
+
   guard.commit();
 }