[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Monotone-commits-diffs] net.venge.monotone: ed8d3ac01eadc609d02f8c14f9b
From: |
code |
Subject: |
[Monotone-commits-diffs] net.venge.monotone: ed8d3ac01eadc609d02f8c14f9b40cb6f6d8ee50 |
Date: |
Thu, 26 Apr 2012 22:40:14 +0200 (CEST) |
revision: ed8d3ac01eadc609d02f8c14f9b40cb6f6d8ee50
date: 2012-04-26T20:33:04
author: address@hidden
branch: net.venge.monotone
changelog:
explicit merge of '0dbadd976b0d29ec72c15be03a68a700f412cd0f'
and '7338faf653922c1c9ce0eb944f8c7c00f5e54bfd'
manifest:
format_version "1"
new_manifest [f6a7530e713ecabbf8bb1b5739b89f8839af5bad]
old_revision [0dbadd976b0d29ec72c15be03a68a700f412cd0f]
patch "src/unix/fs.cc"
from [030ebb81f78bc138de3cf89e3ace8e9dcde2309c]
to [d34f7ed4b5cf3655d7920568e4e1a146fa670e13]
old_revision [7338faf653922c1c9ce0eb944f8c7c00f5e54bfd]
patch "NEWS"
from [5514332f7c16430d0c46d3fbac01b0c8a96bc412]
to [e2f75fe4e775336683ea15030378d9c771ead705]
patch "doc/monotone.texi"
from [e0b88a30f08867f9e0f593e5004789ca17753a94]
to [cba3f164198269415f0996a7211dea6e7e24a3dc]
patch "src/ancestry.cc"
from [8b3388b690a5f4878bd29d752c3e6e073411739e]
to [e673b17a5d2fad2716f7f4efe33c2ca11c7c31f9]
patch "src/revision.hh"
from [740c4dd4ee350fcf06af3ba707cef3dadecb46f8]
to [8d93883e8a6de779aa199d9b2e1aa58589f0626c]
patch "src/selectors.cc"
from [588c6b5fd3ded29f5f778a78e707352564acbc02]
to [19a82c64f44ab5433354299f84598174cb15f510]
patch "test/func/extended-selectors/__driver__.lua"
from [cab379ef6f3439ab7f5a4424202ebf9097171c4c]
to [e80ed8e831bbc9cc346e7722c9877d32887104ef]
============================================================
--- src/unix/fs.cc 030ebb81f78bc138de3cf89e3ace8e9dcde2309c
+++ src/unix/fs.cc d34f7ed4b5cf3655d7920568e4e1a146fa670e13
@@ -1,4 +1,3 @@
-// Copyright (C) 2012 Stephe Leake <address@hidden>
// Copyright (C) 2005 nathaniel smith <address@hidden>
//
// This program is made available under the GNU GPL version 2.0 or
@@ -29,7 +28,6 @@
#include "../platform.hh"
#include "../vector.hh"
-using std::malloc;
using std::string;
using std::vector;
@@ -290,74 +288,11 @@ rename_clobberingly(string const & from,
void
rename_clobberingly(string const & from, string const & to)
{
- // rename doesn't work across devices, which can happen if part of the
- // workspace is NFS mounted.
- //
- // We only check for that if rename fails, to avoid slowing down normal
- // workspaces.
-
if (rename(from.c_str(), to.c_str()))
{
- // rename failed
- int err = errno;
-
- int from_fd = open(from.c_str(), O_RDONLY);
- int to_fd = open(to.c_str(), O_WRONLY | O_CREAT | O_TRUNC);
- struct stat from_stat;
- struct stat to_stat;
- fstat(from_fd, &from_stat);
- fstat(to_fd, &to_stat);
-
- if (from_stat.st_dev /= to_stat.st_dev)
- {
- // different devices; use cp, rm
- //
- // except there isn't a C function that does 'cp', so we read in
- // the file and write it out again.
-
- char * buffer = (char * )malloc(from_stat.st_size);
- char * ptr = buffer;
- size_t remaining = from_stat.st_size;
-
- do
- {
- ssize_t read_count = read(from_fd, ptr, remaining);
-
- err = errno;
-
- E(read_count >= 0, origin::system,
- F ("error reading file '%s': %s") % from % os_strerror(err));
-
- remaining -= read_count;
- ptr += read_count;
- }
- while (remaining > 0);
- close(from_fd);
-
- ptr = buffer;
- remaining = from_stat.st_size;
- do
- {
- ssize_t write_count = write(to_fd, ptr, remaining);
- err = errno;
- E(write_count >= 0, origin::system,
- F("error writing file '%s': %s") % to % os_strerror(err));
-
- remaining -= write_count;
- ptr += write_count;
- }
- while (remaining > 0);
- close(to_fd);
-
- free(buffer);
-
- remove(from.c_str());
- }
- else
- {
- E(false, origin::system,
- F("renaming '%s' to '%s' failed: %s") % from % to % os_strerror(err));
- }
+ const int err = errno;
+ E(false, origin::system,
+ F("renaming '%s' to '%s' failed: %s") % from % to % os_strerror(err));
}
}
============================================================
--- NEWS 5514332f7c16430d0c46d3fbac01b0c8a96bc412
+++ NEWS e2f75fe4e775336683ea15030378d9c771ead705
@@ -10,6 +10,10 @@ XXX XXX XX XX:XX:XX UTC 201X
and returns the attributes for a specific file from the
revision's manifest
+ - New 'min(A)' selector is now available which returns all
+ revisions selected by A which are not descendants of other
+ revisions selected by A.
+
- New 'not(A)' selector is now available which returns all
revisions not selected by 'A'.
============================================================
--- doc/monotone.texi e0b88a30f08867f9e0f593e5004789ca17753a94
+++ doc/monotone.texi cba3f164198269415f0996a7211dea6e7e24a3dc
@@ -2957,6 +2957,11 @@ @heading Composite selectors
@code{max(b:net.venge.monotone/a:graydon)} would return the latest revision(s)
on branch @code{net.venge.monotone} which have an @code{author} cert beginning
with @code{graydon}.
address@hidden min(A)
+Erase descendants; this returns all revisions selected by @code{A} which are not
+descendants of other revisions selected by @code{A}. For example,
address@hidden(b:net.venge.monotone)} would return the earliest revision(s)
+on branch @code{net.venge.monotone}.
@item ancestors(A)
Strict ancestors; returns all revisions which are an ancestor of a revision
selected by @code{A}. For example, @code{ancestors(b:net.venge.monotone)}
============================================================
--- src/ancestry.cc 8b3388b690a5f4878bd29d752c3e6e073411739e
+++ src/ancestry.cc e673b17a5d2fad2716f7f4efe33c2ca11c7c31f9
@@ -374,6 +374,121 @@ erase_ancestors(database & db, set<revis
erase_ancestors_and_failures(db, revisions, p);
}
+static void
+accumulate_strict_descendants(database & db,
+ revision_id const & start,
+ set<revision_id> & all_descendants,
+ multimap<revision_id, revision_id> const & graph,
+ rev_height const & max_height)
+{
+ typedef multimap<revision_id, revision_id>::const_iterator gi;
+
+ vector<revision_id> frontier;
+ frontier.push_back(start);
+
+ while (!frontier.empty())
+ {
+ revision_id rid = frontier.back();
+ frontier.pop_back();
+ pair<gi, gi> parents = graph.equal_range(rid);
+ for (gi i = parents.first; i != parents.second; ++i)
+ {
+ revision_id const & parent = i->second;
+ if (all_descendants.find(parent) == all_descendants.end())
+ {
+ // prune if we're above max_height
+ rev_height h;
+ db.get_rev_height(parent, h);
+ if (h <= max_height)
+ {
+ all_descendants.insert(parent);
+ frontier.push_back(parent);
+ }
+ }
+ }
+ }
+}
+
+// this call is equivalent to running:
+// erase(remove_if(candidates.begin(), candidates.end(), p));
+// erase_descendants(candidates, db);
+// however, by interleaving the two operations, it can in common cases make
+// many fewer calls to the predicate, which can be a significant speed win.
+
+void
+erase_descendants_and_failures(database & db,
+ std::set<revision_id> & candidates,
+ is_failure & p,
+ multimap<revision_id, revision_id> *graph_cache_ptr)
+{
+ // Load up the ancestry graph
+ multimap<revision_id, revision_id> graph;
+
+ if (candidates.empty())
+ return;
+
+ if (graph_cache_ptr == NULL)
+ graph_cache_ptr = &graph;
+ if (graph_cache_ptr->empty())
+ {
+ db.get_forward_ancestry(*graph_cache_ptr);
+ }
+
+ // Keep a set of all descendants that we've traversed -- to avoid
+ // combinatorial explosion.
+ set<revision_id> all_descendants;
+
+ rev_height max_height;
+ db.get_rev_height(*candidates.begin(), max_height);
+ for (std::set<revision_id>::const_iterator it = candidates.begin(); it != candidates.end(); it++)
+ {
+ rev_height h;
+ db.get_rev_height(*it, h);
+ if (h > max_height)
+ max_height = h;
+ }
+
+ vector<revision_id> todo(candidates.begin(), candidates.end());
+ std::random_shuffle(todo.begin(), todo.end());
+
+ size_t predicates = 0;
+ while (!todo.empty())
+ {
+ revision_id rid = todo.back();
+ todo.pop_back();
+ // check if this one has already been eliminated
+ if (all_descendants.find(rid) != all_descendants.end())
+ continue;
+ // and then whether it actually should stay in the running:
+ ++predicates;
+ if (p(rid))
+ {
+ candidates.erase(rid);
+ continue;
+ }
+ // okay, it is good enough that all its descendants should be
+ // eliminated
+ accumulate_strict_descendants(db, rid, all_descendants, *graph_cache_ptr, max_height);
+ }
+
+ // now go and eliminate the ancestors
+ for (set<revision_id>::const_iterator i = all_descendants.begin();
+ i != all_descendants.end(); ++i)
+ candidates.erase(*i);
+
+ L(FL("called predicate %s times") % predicates);
+}
+
+// This function looks at a set of revisions, and for every pair A, B in that
+// set such that A is an descendant of B, it erases A.
+
+void
+erase_descendants(database & db, set<revision_id> & revisions)
+{
+ no_failures p;
+ erase_descendants_and_failures(db, revisions, p);
+}
+
// This function takes a revision A and a set of revision Bs, calculates the
// ancestry of each, and returns the set of revisions that are in A's ancestry
// but not in the ancestry of any of the Bs. It tells you 'what's new' in A
============================================================
--- src/revision.hh 740c4dd4ee350fcf06af3ba707cef3dadecb46f8
+++ src/revision.hh 8d93883e8a6de779aa199d9b2e1aa58589f0626c
@@ -162,6 +162,15 @@ void
std::multimap<revision_id, revision_id> *inverse_graph_cache_ptr = NULL);
void
+erase_descendants(database & db, std::set<revision_id> & revisions);
+
+void
+erase_descendants_and_failures(database & db,
+ std::set<revision_id> & revisions,
+ is_failure & p,
+ std::multimap<revision_id, revision_id> *inverse_graph_cache_ptr = NULL);
+
+void
ancestry_difference(database & db, revision_id const & a,
std::set<revision_id> const & bs,
std::set<revision_id> & new_stuff);
============================================================
--- src/selectors.cc 588c6b5fd3ded29f5f778a78e707352564acbc02
+++ src/selectors.cc 19a82c64f44ab5433354299f84598174cb15f510
@@ -559,6 +559,13 @@ public:
erase_ancestors(project.db, ret);
return ret;
}
+ else if (name == "min")
+ {
+ diagnose_wrong_arg_count("min", 1, args.size());
+ set<revision_id> ret = args[0]->complete(project);
+ erase_descendants(project.db, ret);
+ return ret;
+ }
else if (name == "ancestors")
{
diagnose_wrong_arg_count("ancestors", 1, args.size());
============================================================
--- test/func/extended-selectors/__driver__.lua cab379ef6f3439ab7f5a4424202ebf9097171c4c
+++ test/func/extended-selectors/__driver__.lua e80ed8e831bbc9cc346e7722c9877d32887104ef
@@ -3,6 +3,7 @@
-- not(a)
-- lca(a,b)
-- max(a)
+-- min(a)
-- ancestors(a)
-- descendants(a)
-- parents(a)
@@ -79,6 +80,12 @@ expect("b:testbranch|b:otherbranch", roo
expect("b:testbranch/b:otherbranch", lhs)
expect("b:testbranch|b:otherbranch", root, lhs, rhs, m, other, other_2)
+expect("min(*)", root)
+expect("min(b:testbranch)", root)
+expect("min(b:testbranch/a:Anne)", rhs)
+expect("min(b:otherbranch)", lhs)
+expect("min(a:Jim)", other)
+
-- now do same tests again with a double not - should get same results
expect("not(not(b:testbranch))", root, lhs, rhs, m)
expect("not(not(b:otherbranch))", lhs, other, other_2)
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Monotone-commits-diffs] net.venge.monotone: ed8d3ac01eadc609d02f8c14f9b40cb6f6d8ee50,
code <=