#
#
# add_file "branch.cc"
# content [feebd0dcee184b06da556c39804f799df62004d1]
#
# add_file "branch.hh"
# content [f913da1a88fee4f7943411cb8d03a11655ca5d2e]
#
# add_file "outdated_indicator.cc"
# content [5aec489052b464a928cadf8915478177f7ee8196]
#
# add_file "outdated_indicator.hh"
# content [1e93604846e99249f6f6e31544b39d6fb576a3ab]
#
# patch "ChangeLog"
# from [17b3fafd9646930a3de6c6613c11398ac0dcdd31]
# to [e2c18e954bbf2da27e8e25e744955774a1fddc9f]
#
# patch "Makefile.am"
# from [54ead20fb82676cc06060406a7ff85fcc63d92e8]
# to [a1bb9b6a8e0323dab754103d76ff302fa08cb6e6]
#
# patch "app_state.cc"
# from [3f05dfd982acfdbfc89686994668285190de5933]
# to [c51dd3ba75b38b6f0c624470f5b88f976c3b1deb]
#
# patch "app_state.hh"
# from [bd83327f6bfc72eb55500a114abf147b687f5c79]
# to [542ae07fd61ea2002549a185189c0db1235613bc]
#
# patch "automate.cc"
# from [d84bcc2a3343891d6702ac80c8c00672aea6037b]
# to [7d5b68647c134c094323e2ac3793d887211547a0]
#
# patch "cert.cc"
# from [5936182817276e51a90b8be71753cd5ae3eb6d9e]
# to [7b6c1ee29936bcdcb470a76fa415a750c77bc51a]
#
# patch "cert.hh"
# from [797765e33d5bec49457a3ff0e09374ee6317949c]
# to [9802985dc9185a37739575d5a4c84d41f4acd286]
#
# patch "cmd_merging.cc"
# from [f578cdba90e5b74d001e48bab8db95870c04fce9]
# to [6cf691238da422820cb4e59a05e0174a54548c93]
#
# patch "cmd_ws_commit.cc"
# from [7c6997b990823c878080f41b0428b2543fa0c896]
# to [b7434c5291a0c867f38fdbff6a1a7bae50a90cbb]
#
# patch "database.cc"
# from [2d10672483bebf2fffbd7c1ac0edf6ddbe322f98]
# to [63484ce0117ff482396a9371445363bd8071dab4]
#
# patch "database.hh"
# from [bbf8e39a0adaa28a4694549d26602b3712f6109c]
# to [90b06ee358aefaec065b5e7a7ac645f112dade68]
#
============================================================
--- branch.cc feebd0dcee184b06da556c39804f799df62004d1
+++ branch.cc feebd0dcee184b06da556c39804f799df62004d1
@@ -0,0 +1,19 @@
+// 2007 Timothy Brownawell
+// GNU GPL V2 or later
+
+#include "branch.hh"
+#include "cert.hh"
+
+branch::branch(app_state & app, utf8 const & name)
+ : app(app), name(name)
+{}
+
+void
+branch::heads(std::set & h)
+{
+ if (stamp.outdated())
+ {
+ stamp = get_branch_heads(name(), app, _heads);
+ }
+ h = _heads;
+}
============================================================
--- branch.hh f913da1a88fee4f7943411cb8d03a11655ca5d2e
+++ branch.hh f913da1a88fee4f7943411cb8d03a11655ca5d2e
@@ -0,0 +1,26 @@
+// 2007 Timothy Brownawell
+// GNU GPL V2 or later
+
+#ifndef __BRANCH_HH__
+#define __BRANCH_HH__
+
+#include
+
+#include "outdated_indicator.hh"
+#include "vocab.hh"
+
+class app_state;
+
+class branch
+{
+ app_state & app;
+ utf8 name;
+ outdated_indicator stamp;
+ std::set _heads;
+public:
+ branch(app_state & app, utf8 const & name);
+
+ void heads(std::set & h);
+};
+
+#endif
============================================================
--- outdated_indicator.cc 5aec489052b464a928cadf8915478177f7ee8196
+++ outdated_indicator.cc 5aec489052b464a928cadf8915478177f7ee8196
@@ -0,0 +1,108 @@
+// 2007 Timothy Brownawell
+// GNU GPL V2 or later
+
+#include "outdated_indicator.hh"
+#include "sanity.hh"
+
+class outdated_indicator_factory_impl
+{
+ unsigned int changed;
+ unsigned int dispensed;
+public:
+ outdated_indicator_factory_impl();
+ void note_change();
+ unsigned int last_change() const;
+ unsigned int dispense();
+};
+
+outdated_indicator_factory_impl::outdated_indicator_factory_impl()
+ : changed(0), dispensed(0)
+{}
+
+unsigned int
+outdated_indicator_factory_impl::last_change() const
+{
+ return changed;
+}
+
+unsigned int
+outdated_indicator_factory_impl::dispense()
+{
+ I(changed == dispensed || changed == dispensed + 1);
+ dispensed = changed;
+ return dispensed;
+}
+
+void
+outdated_indicator_factory_impl::note_change()
+{
+ I(changed == dispensed || changed == dispensed + 1);
+ if (changed == dispensed)
+ ++changed;
+}
+
+
+outdated_indicator::outdated_indicator()
+ : parent(), when(0)
+{}
+
+outdated_indicator::outdated_indicator(boost::shared_ptr p)
+ : parent(p), when(p->dispense())
+{}
+
+bool
+outdated_indicator::outdated()
+{
+ if (parent)
+ {
+ I(when <= parent->last_change());
+ return when < parent->last_change();
+ }
+ else
+ return true;
+}
+
+
+outdated_indicator_factory::outdated_indicator_factory()
+ : impl(new outdated_indicator_factory_impl)
+{}
+
+outdated_indicator_factory::~outdated_indicator_factory()
+{
+ impl->note_change();
+}
+
+outdated_indicator
+outdated_indicator_factory::get_notifier()
+{
+ return outdated_indicator(impl);
+}
+
+void
+outdated_indicator_factory::note_change()
+{
+ impl->note_change();
+}
+
+#ifdef BUILD_UNIT_TESTS
+#include "unit_tests.hh"
+
+UNIT_TEST(outdated_indicator, )
+{
+ outdated_indicator indicator;
+ {
+ outdated_indicator_factory factory;
+ BOOST_CHECK(indicator.outdated());
+ indicator = factory.get_notifier();
+ BOOST_CHECK(!indicator.outdated());
+ factory.note_change();
+ BOOST_CHECK(indicator.outdated());
+ factory.note_change();
+ factory.note_change();
+ indicator = factory.get_notifier();
+ BOOST_CHECK(!indicator.outdated());
+ }
+ BOOST_CHECK(indicator.outdated());
+}
+
+#endif
============================================================
--- outdated_indicator.hh 1e93604846e99249f6f6e31544b39d6fb576a3ab
+++ outdated_indicator.hh 1e93604846e99249f6f6e31544b39d6fb576a3ab
@@ -0,0 +1,44 @@
+#ifndef __OUTDATED_NOTIFIER_HH__
+#define __OUTDATED_NOTIFIER_HH__
+
+// 2007 Timothy Brownawell
+// GNU GPL V2 or later
+
+// Allow clients to find out when something changes.
+// The 'something' has an outdated_indicator_factory,
+// and calls note_change() when changes are made.
+// The client is provided with an outdated_indicator made
+// from that factory, which will become outdated after
+// further changes are made to the something.
+
+// The default indicator is always outdated.
+
+// When a factory is destroyed, all indicators made from
+// that factory become outdated.
+
+#include
+
+class outdated_indicator_factory_impl;
+
+class outdated_indicator
+{
+ boost::shared_ptr parent;
+ unsigned int when;
+public:
+ outdated_indicator();
+ explicit outdated_indicator(boost::shared_ptr p);
+ bool outdated();
+};
+
+
+class outdated_indicator_factory
+{
+ boost::shared_ptr impl;
+public:
+ outdated_indicator_factory();
+ ~outdated_indicator_factory();
+ outdated_indicator get_notifier();
+ void note_change();
+};
+
+#endif
============================================================
--- ChangeLog 17b3fafd9646930a3de6c6613c11398ac0dcdd31
+++ ChangeLog e2c18e954bbf2da27e8e25e744955774a1fddc9f
@@ -1,3 +1,16 @@
+2007-01-09 Timothy Brownawell
+
+ * outdated_indicator.{cc,hh}: Allows code that caches replys to
+ find out when those replys may be outdated. Used by...
+ * branch.{cc,hh}: Give us a concept of a 'branch'. Currently, this
+ only lets you find branch heads. Branch heads are cached and only
+ recalculated if certs have been added to / removed from the db.
+ * database.{cc,hh}: Enable the use of outdated_indicator s for
+ operations that return sets of certs.
+ * many: Use the new way to calculate heads. Right now, the main
+ effect is that 'automate heads' of the same branch is very fast
+ on subsequent calls from 'automate stdio'.
+
2007-01-06 Thomas Keller
* cmd_automate.cc: automate stdio now opens the database
============================================================
--- Makefile.am 54ead20fb82676cc06060406a7ff85fcc63d92e8
+++ Makefile.am a1bb9b6a8e0323dab754103d76ff302fa08cb6e6
@@ -33,6 +33,8 @@ MOST_SOURCES = \
update.cc update.hh \
work.cc work_migration.cc work.hh \
cert.cc cert.hh \
+ branch.cc branch.hh \
+ outdated_indicator.cc outdated_indicator.hh \
database.cc database.hh \
key_store.cc key_store.hh \
localized_file_io.cc localized_file_io.hh \
============================================================
--- app_state.cc 3f05dfd982acfdbfc89686994668285190de5933
+++ app_state.cc c51dd3ba75b38b6f0c624470f5b88f976c3b1deb
@@ -193,6 +193,14 @@ app_state::make_branch_sticky()
}
}
+branch &
+app_state::get_branch(utf8 const & name)
+{
+ std::pair::iterator, bool> res;
+ res = branch_map.insert(std::make_pair(name, branch(*this, name)));
+ return res.first->second;
+}
+
void
app_state::set_root(system_path const & path)
{
============================================================
--- app_state.hh bd83327f6bfc72eb55500a114abf147b687f5c79
+++ app_state.hh 542ae07fd61ea2002549a185189c0db1235613bc
@@ -19,6 +19,7 @@ class lua_hooks;
#include
#include
+#include "branch.hh"
#include "database.hh"
#include "key_store.hh"
#include "lua_hooks.hh"
@@ -80,6 +81,11 @@ public:
void make_branch_sticky();
+private:
+ std::map branch_map;
+public:
+ branch & get_branch(utf8 const & name);
+
void set_database(system_path const & filename);
void set_key_dir(system_path const & filename);
void set_root(system_path const & root);
============================================================
--- automate.cc d84bcc2a3343891d6702ac80c8c00672aea6037b
+++ automate.cc 7d5b68647c134c094323e2ac3793d887211547a0
@@ -71,7 +71,7 @@ AUTOMATE(heads, N_("[BRANCH]"), options:
app.opts.branch_name = idx(args, 0);
}
set heads;
- get_branch_heads(app.opts.branch_name(), app, heads);
+ app.get_branch(app.opts.branch_name()).heads(heads);
for (set::const_iterator i = heads.begin(); i != heads.end(); ++i)
output << (*i).inner()() << "\n";
}
============================================================
--- cert.cc 5936182817276e51a90b8be71753cd5ae3eb6d9e
+++ cert.cc 7b6c1ee29936bcdcb470a76fa415a750c77bc51a
@@ -565,7 +565,7 @@ namespace
};
}
-void
+outdated_indicator
get_branch_heads(cert_value const & branchname,
app_state & app,
set & heads)
@@ -574,13 +574,15 @@ get_branch_heads(cert_value const & bran
base64 branch_encoded;
encode_base64(branchname, branch_encoded);
- app.db.get_revisions_with_cert(cert_name(branch_cert_name),
- branch_encoded,
- heads);
+ outdated_indicator stamp;
+ stamp = app.db.get_revisions_with_cert(cert_name(branch_cert_name),
+ branch_encoded,
+ heads);
not_in_branch p(app, branch_encoded);
erase_ancestors_and_failures(heads, p, app);
L(FL("found heads of branch %s (%s heads)") % branchname % heads.size());
+ return stamp;
}
============================================================
--- cert.hh 797765e33d5bec49457a3ff0e09374ee6317949c
+++ cert.hh 9802985dc9185a37739575d5a4c84d41f4acd286
@@ -17,6 +17,7 @@
#include
#include
+#include "outdated_indicator.hh"
#include "vocab.hh"
// Certs associate an opaque name/value pair with a revision ID, and
@@ -89,7 +90,7 @@ cert_revision_in_branch(revision_id cons
app_state & app,
packet_consumer & pc);
-void
+outdated_indicator
get_branch_heads(cert_value const & branchname,
app_state & app,
std::set & heads);
============================================================
--- cmd_merging.cc f578cdba90e5b74d001e48bab8db95870c04fce9
+++ cmd_merging.cc 6cf691238da422820cb4e59a05e0174a54548c93
@@ -330,7 +330,7 @@ CMD(merge, N_("tree"), "", N_("merge unm
F("please specify a branch, with --branch=BRANCH"));
set heads;
- get_branch_heads(app.opts.branch_name(), app, heads);
+ app.get_branch(app.opts.branch_name()).heads(heads);
N(heads.size() != 0, F("branch '%s' is empty") % app.opts.branch_name);
if (heads.size() == 1)
@@ -398,7 +398,7 @@ CMD(merge, N_("tree"), "", N_("merge unm
ancestors.clear();
heads_for_ancestor.clear();
- get_branch_heads(app.opts.branch_name(), app, heads);
+ app.get_branch(app.opts.branch_name()).heads(heads);
pass++;
}
@@ -463,8 +463,8 @@ CMD(merge_into_dir, N_("tree"), N_("SOUR
if (args.size() != 3)
throw usage(name);
- get_branch_heads(idx(args, 0)(), app, src_heads);
- get_branch_heads(idx(args, 1)(), app, dst_heads);
+ app.get_branch(idx(args, 0)()).heads(src_heads);
+ app.get_branch(idx(args, 1)()).heads(dst_heads);
N(src_heads.size() != 0, F("branch '%s' is empty") % idx(args, 0)());
N(src_heads.size() == 1, F("branch '%s' is not merged") % idx(args, 0)());
@@ -828,7 +828,7 @@ CMD(heads, N_("tree"), "", N_("show unme
N(app.opts.branch_name() != "",
F("please specify a branch, with --branch=BRANCH"));
- get_branch_heads(app.opts.branch_name(), app, heads);
+ app.get_branch(app.opts.branch_name()).heads(heads);
if (heads.size() == 0)
P(F("branch '%s' is empty") % app.opts.branch_name);
============================================================
--- cmd_ws_commit.cc 7c6997b990823c878080f41b0428b2543fa0c896
+++ cmd_ws_commit.cc b7434c5291a0c867f38fdbff6a1a7bae50a90cbb
@@ -502,7 +502,7 @@ CMD(checkout, N_("tree"), N_("[DIRECTORY
F("use --revision or --branch to specify what to checkout"));
set heads;
- get_branch_heads(app.opts.branch_name(), app, heads);
+ app.get_branch(app.opts.branch_name).heads(heads);
N(heads.size() > 0,
F("branch '%s' is empty") % app.opts.branch_name);
if (heads.size() > 1)
@@ -758,7 +758,7 @@ CMD(commit, N_("workspace"), N_("[PATH].
I(restricted_rev.edges.size() == 1);
set heads;
- get_branch_heads(app.opts.branch_name(), app, heads);
+ app.get_branch(app.opts.branch_name).heads(heads);
unsigned int old_head_size = heads.size();
if (app.opts.branch_name() != "")
@@ -931,7 +931,7 @@ CMD(commit, N_("workspace"), N_("[PATH].
app.work.blank_user_log();
- get_branch_heads(app.opts.branch_name(), app, heads);
+ app.get_branch(app.opts.branch_name).heads(heads);
if (heads.size() > old_head_size && old_head_size > 0) {
P(F("note: this revision creates divergence\n"
"note: you may (or may not) wish to run '%s merge'")
@@ -1036,7 +1036,7 @@ CMD_NO_WORKSPACE(import, N_("tree"), N_(
F("use --revision or --branch to specify what to checkout"));
set heads;
- get_branch_heads(app.opts.branch_name(), app, heads);
+ app.get_branch(app.opts.branch_name).heads(heads);
if (heads.size() > 1)
{
P(F("branch %s has multiple heads:") % app.opts.branch_name);
============================================================
--- database.cc 2d10672483bebf2fffbd7c1ac0edf6ddbe322f98
+++ database.cc 63484ce0117ff482396a9371445363bd8071dab4
@@ -1911,6 +1911,7 @@ database::delete_existing_rev_and_certs(
// Kill the certs, ancestry, and revision.
execute(query("DELETE from revision_certs WHERE id = ?")
% text(rid.inner()()));
+ cert_stamper.note_change();
execute(query("DELETE from revision_ancestry WHERE child = ?")
% text(rid.inner()()));
@@ -1931,6 +1932,7 @@ database::delete_branch_named(cert_value
L(FL("Deleting all references to branch %s") % branch);
execute(query("DELETE FROM revision_certs WHERE name='branch' AND value =?")
% blob(branch()));
+ cert_stamper.note_change();
execute(query("DELETE FROM branch_epochs WHERE branch=?")
% blob(branch()));
}
@@ -1942,6 +1944,7 @@ database::delete_tag_named(cert_value co
L(FL("Deleting all references to tag %s") % tag);
execute(query("DELETE FROM revision_certs WHERE name='tag' AND value =?")
% blob(tag()));
+ cert_stamper.note_change();
}
// crypto key management
@@ -2241,10 +2244,12 @@ database::put_revision_cert(revision const & cert)
{
put_cert(cert.inner(), "revision_certs");
+ cert_stamper.note_change();
}
-void database::get_revision_cert_nobranch_index(vector< pair,
- pair > > & idx)
+outdated_indicator
+database::get_revision_cert_nobranch_index(vector< pair,
+ pair > > & idx)
{
results res;
fetch(res, 3, any_rows,
@@ -2259,18 +2264,20 @@ void database::get_revision_cert_nobranc
make_pair(revision_id((*i)[1]),
rsa_keypair_id((*i)[2]))));
}
+ return cert_stamper.get_notifier();
}
-void
+outdated_indicator
database::get_revision_certs(vector< revision > & ts)
{
vector certs;
get_certs(certs, "revision_certs");
ts.clear();
copy(certs.begin(), certs.end(), back_inserter(ts));
+ return cert_stamper.get_notifier();
}
-void
+outdated_indicator
database::get_revision_certs(cert_name const & name,
vector< revision > & ts)
{
@@ -2278,9 +2285,10 @@ database::get_revision_certs(cert_name c
get_certs(name, certs, "revision_certs");
ts.clear();
copy(certs.begin(), certs.end(), back_inserter(ts));
+ return cert_stamper.get_notifier();
}
-void
+outdated_indicator
database::get_revision_certs(revision_id const & id,
cert_name const & name,
vector< revision > & ts)
@@ -2289,9 +2297,10 @@ database::get_revision_certs(revision_id
get_certs(id.inner(), name, certs, "revision_certs");
ts.clear();
copy(certs.begin(), certs.end(), back_inserter(ts));
+ return cert_stamper.get_notifier();
}
-void
+outdated_indicator
database::get_revision_certs(revision_id const & id,
cert_name const & name,
base64 const & val,
@@ -2301,9 +2310,10 @@ database::get_revision_certs(revision_id
get_certs(id.inner(), name, val, certs, "revision_certs");
ts.clear();
copy(certs.begin(), certs.end(), back_inserter(ts));
+ return cert_stamper.get_notifier();
}
-void
+outdated_indicator
database::get_revisions_with_cert(cert_name const & name,
base64 const & val,
set & revisions)
@@ -2316,9 +2326,10 @@ database::get_revisions_with_cert(cert_n
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]));
+ return cert_stamper.get_notifier();
}
-void
+outdated_indicator
database::get_revision_certs(cert_name const & name,
base64 const & val,
vector< revision > & ts)
@@ -2327,9 +2338,10 @@ database::get_revision_certs(cert_name c
get_certs(name, val, certs, "revision_certs");
ts.clear();
copy(certs.begin(), certs.end(), back_inserter(ts));
+ return cert_stamper.get_notifier();
}
-void
+outdated_indicator
database::get_revision_certs(revision_id const & id,
vector< revision > & ts)
{
@@ -2337,9 +2349,10 @@ database::get_revision_certs(revision_id
get_certs(id.inner(), certs, "revision_certs");
ts.clear();
copy(certs.begin(), certs.end(), back_inserter(ts));
+ return cert_stamper.get_notifier();
}
-void
+outdated_indicator
database::get_revision_certs(revision_id const & ident,
vector< hexenc > & ts)
{
@@ -2353,6 +2366,7 @@ database::get_revision_certs(revision_id
ts.clear();
for (size_t i = 0; i < res.size(); ++i)
ts.push_back(hexenc(res[i][0]));
+ return cert_stamper.get_notifier();
}
void
============================================================
--- database.hh bbf8e39a0adaa28a4694549d26602b3712f6109c
+++ database.hh 90b06ee358aefaec065b5e7a7ac645f112dade68
@@ -28,6 +28,7 @@ int sqlite3_finalize(sqlite3_stmt *);
#include "cleanup.hh"
#include "roster.hh"
#include "selectors.hh"
+#include "outdated_indicator.hh"
#include "vocab.hh"
#include "rev_height.hh"
@@ -407,42 +408,44 @@ private:
std::vector & certs,
std::string const & table);
+ outdated_indicator_factory cert_stamper;
public:
+
bool revision_cert_exists(revision const & cert);
bool revision_cert_exists(hexenc const & hash);
void put_revision_cert(revision const & cert);
// this variant has to be rather coarse and fast, for netsync's use
- void get_revision_cert_nobranch_index(std::vector< std::pair,
- std::pair > > & idx);
+ outdated_indicator get_revision_cert_nobranch_index(std::vector< std::pair,
+ std::pair > > & idx);
- void get_revision_certs(std::vector< revision > & certs);
+ outdated_indicator get_revision_certs(std::vector< revision > & certs);
- void get_revision_certs(cert_name const & name,
+ outdated_indicator get_revision_certs(cert_name const & name,
std::vector< revision > & certs);
- void get_revision_certs(revision_id const & ident,
+ outdated_indicator get_revision_certs(revision_id const & ident,
cert_name const & name,
std::vector< revision > & certs);
- void get_revision_certs(cert_name const & name,
+ outdated_indicator get_revision_certs(cert_name const & name,
base64 const & val,
std::vector< revision > & certs);
- void get_revision_certs(revision_id const & ident,
+ outdated_indicator get_revision_certs(revision_id const & ident,
cert_name const & name,
base64 const & value,
std::vector< revision > & certs);
- void get_revisions_with_cert(cert_name const & name,
+ outdated_indicator get_revisions_with_cert(cert_name const & name,
base64 const & value,
std::set & revisions);
- void get_revision_certs(revision_id const & ident,
+ outdated_indicator get_revision_certs(revision_id const & ident,
std::vector< revision > & certs);
- void get_revision_certs(revision_id const & ident,
+ outdated_indicator get_revision_certs(revision_id const & ident,
std::vector< hexenc > & hashes);
void get_revision_cert(hexenc const & hash,