##// END OF EJS Templates
rust-discovery: optionally don't randomize at all, for tests...
Georges Racinet -
r42968:4e7bd618 default
parent child Browse files
Show More
@@ -92,11 +92,19 b' def _updatesample(revs, heads, sample, p'
92 dist.setdefault(p, d + 1)
92 dist.setdefault(p, d + 1)
93 visit.append(p)
93 visit.append(p)
94
94
95 def _limitsample(sample, desiredlen):
95 def _limitsample(sample, desiredlen, randomize=True):
96 """return a random subset of sample of at most desiredlen item"""
96 """return a random subset of sample of at most desiredlen item.
97 if len(sample) > desiredlen:
97
98 sample = set(random.sample(sample, desiredlen))
98 If randomize is False, though, a deterministic subset is returned.
99 return sample
99 This is meant for integration tests.
100 """
101 if len(sample) <= desiredlen:
102 return sample
103 if randomize:
104 return set(random.sample(sample, desiredlen))
105 sample = list(sample)
106 sample.sort()
107 return set(sample[:desiredlen])
100
108
101 class partialdiscovery(object):
109 class partialdiscovery(object):
102 """an object representing ongoing discovery
110 """an object representing ongoing discovery
@@ -110,7 +118,7 b' class partialdiscovery(object):'
110 (all tracked revisions are known locally)
118 (all tracked revisions are known locally)
111 """
119 """
112
120
113 def __init__(self, repo, targetheads, respectsize):
121 def __init__(self, repo, targetheads, respectsize, randomize=True):
114 self._repo = repo
122 self._repo = repo
115 self._targetheads = targetheads
123 self._targetheads = targetheads
116 self._common = repo.changelog.incrementalmissingrevs()
124 self._common = repo.changelog.incrementalmissingrevs()
@@ -118,6 +126,7 b' class partialdiscovery(object):'
118 self.missing = set()
126 self.missing = set()
119 self._childrenmap = None
127 self._childrenmap = None
120 self._respectsize = respectsize
128 self._respectsize = respectsize
129 self.randomize = randomize
121
130
122 def addcommons(self, commons):
131 def addcommons(self, commons):
123 """register nodes known as common"""
132 """register nodes known as common"""
@@ -222,7 +231,7 b' class partialdiscovery(object):'
222 sample = set(self._repo.revs('heads(%ld)', revs))
231 sample = set(self._repo.revs('heads(%ld)', revs))
223
232
224 if len(sample) >= size:
233 if len(sample) >= size:
225 return _limitsample(sample, size)
234 return _limitsample(sample, size, randomize=self.randomize)
226
235
227 _updatesample(None, headrevs, sample, self._parentsgetter(),
236 _updatesample(None, headrevs, sample, self._parentsgetter(),
228 quicksamplesize=size)
237 quicksamplesize=size)
@@ -249,10 +258,15 b' class partialdiscovery(object):'
249 if not self._respectsize:
258 if not self._respectsize:
250 size = max(size, min(len(revsroots), len(revsheads)))
259 size = max(size, min(len(revsroots), len(revsheads)))
251
260
252 sample = _limitsample(sample, size)
261 sample = _limitsample(sample, size, randomize=self.randomize)
253 if len(sample) < size:
262 if len(sample) < size:
254 more = size - len(sample)
263 more = size - len(sample)
255 sample.update(random.sample(list(revs - sample), more))
264 takefrom = list(revs - sample)
265 if self.randomize:
266 sample.update(random.sample(takefrom, more))
267 else:
268 takefrom.sort()
269 sample.update(takefrom[:more])
256 return sample
270 return sample
257
271
258 def findcommonheads(ui, local, remote,
272 def findcommonheads(ui, local, remote,
@@ -31,6 +31,7 b' pub struct PartialDiscovery<G: Graph + C'
31 missing: HashSet<Revision>,
31 missing: HashSet<Revision>,
32 rng: Rng,
32 rng: Rng,
33 respect_size: bool,
33 respect_size: bool,
34 randomize: bool,
34 }
35 }
35
36
36 pub struct DiscoveryStats {
37 pub struct DiscoveryStats {
@@ -151,14 +152,26 b' impl<G: Graph + Clone> PartialDiscovery<'
151 /// will interpret the size argument requested by the caller. If it's
152 /// will interpret the size argument requested by the caller. If it's
152 /// `false`, they are allowed to produce a sample whose size is more
153 /// `false`, they are allowed to produce a sample whose size is more
153 /// appropriate to the situation (typically bigger).
154 /// appropriate to the situation (typically bigger).
155 ///
156 /// The `randomize` boolean affects sampling, and specifically how
157 /// limiting or last-minute expanding is been done:
158 ///
159 /// If `true`, both will perform random picking from `self.undecided`.
160 /// This is currently the best for actual discoveries.
161 ///
162 /// If `false`, a reproductible picking strategy is performed. This is
163 /// useful for integration tests.
154 pub fn new(
164 pub fn new(
155 graph: G,
165 graph: G,
156 target_heads: Vec<Revision>,
166 target_heads: Vec<Revision>,
157 respect_size: bool,
167 respect_size: bool,
168 randomize: bool,
158 ) -> Self {
169 ) -> Self {
159 let mut seed: [u8; 16] = [0; 16];
170 let mut seed: [u8; 16] = [0; 16];
160 thread_rng().fill_bytes(&mut seed);
171 if randomize {
161 Self::new_with_seed(graph, target_heads, seed, respect_size)
172 thread_rng().fill_bytes(&mut seed);
173 }
174 Self::new_with_seed(graph, target_heads, seed, respect_size, randomize)
162 }
175 }
163
176
164 pub fn new_with_seed(
177 pub fn new_with_seed(
@@ -166,6 +179,7 b' impl<G: Graph + Clone> PartialDiscovery<'
166 target_heads: Vec<Revision>,
179 target_heads: Vec<Revision>,
167 seed: [u8; 16],
180 seed: [u8; 16],
168 respect_size: bool,
181 respect_size: bool,
182 randomize: bool,
169 ) -> Self {
183 ) -> Self {
170 PartialDiscovery {
184 PartialDiscovery {
171 undecided: None,
185 undecided: None,
@@ -176,6 +190,7 b' impl<G: Graph + Clone> PartialDiscovery<'
176 missing: HashSet::new(),
190 missing: HashSet::new(),
177 rng: Rng::from_seed(seed),
191 rng: Rng::from_seed(seed),
178 respect_size: respect_size,
192 respect_size: respect_size,
193 randomize: randomize,
179 }
194 }
180 }
195 }
181
196
@@ -186,6 +201,11 b' impl<G: Graph + Clone> PartialDiscovery<'
186 mut sample: Vec<Revision>,
201 mut sample: Vec<Revision>,
187 size: usize,
202 size: usize,
188 ) -> Vec<Revision> {
203 ) -> Vec<Revision> {
204 if !self.randomize {
205 sample.sort();
206 sample.truncate(size);
207 return sample;
208 }
189 let sample_len = sample.len();
209 let sample_len = sample.len();
190 if sample_len <= size {
210 if sample_len <= size {
191 return sample;
211 return sample;
@@ -436,13 +456,15 b' mod tests {'
436
456
437 /// A PartialDiscovery as for pushing all the heads of `SampleGraph`
457 /// A PartialDiscovery as for pushing all the heads of `SampleGraph`
438 ///
458 ///
439 /// To avoid actual randomness in tests, we give it a fixed random seed.
459 /// To avoid actual randomness in these tests, we give it a fixed
460 /// random seed, but by default we'll test the random version.
440 fn full_disco() -> PartialDiscovery<SampleGraph> {
461 fn full_disco() -> PartialDiscovery<SampleGraph> {
441 PartialDiscovery::new_with_seed(
462 PartialDiscovery::new_with_seed(
442 SampleGraph,
463 SampleGraph,
443 vec![10, 11, 12, 13],
464 vec![10, 11, 12, 13],
444 [0; 16],
465 [0; 16],
445 true,
466 true,
467 true,
446 )
468 )
447 }
469 }
448
470
@@ -450,7 +472,13 b' mod tests {'
450 ///
472 ///
451 /// To avoid actual randomness in tests, we give it a fixed random seed.
473 /// To avoid actual randomness in tests, we give it a fixed random seed.
452 fn disco12() -> PartialDiscovery<SampleGraph> {
474 fn disco12() -> PartialDiscovery<SampleGraph> {
453 PartialDiscovery::new_with_seed(SampleGraph, vec![12], [0; 16], true)
475 PartialDiscovery::new_with_seed(
476 SampleGraph,
477 vec![12],
478 [0; 16],
479 true,
480 true,
481 )
454 }
482 }
455
483
456 fn sorted_undecided(
484 fn sorted_undecided(
@@ -535,6 +563,16 b' mod tests {'
535 }
563 }
536
564
537 #[test]
565 #[test]
566 fn test_limit_sample_no_random() {
567 let mut disco = full_disco();
568 disco.randomize = false;
569 assert_eq!(
570 disco.limit_sample(vec![1, 8, 13, 5, 7, 3], 4),
571 vec![1, 3, 5, 7]
572 );
573 }
574
575 #[test]
538 fn test_quick_sample_enough_undecided_heads() -> Result<(), GraphError> {
576 fn test_quick_sample_enough_undecided_heads() -> Result<(), GraphError> {
539 let mut disco = full_disco();
577 let mut disco = full_disco();
540 disco.undecided = Some((1..=13).collect());
578 disco.undecided = Some((1..=13).collect());
@@ -36,7 +36,8 b' py_class!(pub class PartialDiscovery |py'
36 _cls,
36 _cls,
37 repo: PyObject,
37 repo: PyObject,
38 targetheads: PyObject,
38 targetheads: PyObject,
39 respectsize: bool
39 respectsize: bool,
40 randomize: bool = true
40 ) -> PyResult<PartialDiscovery> {
41 ) -> PyResult<PartialDiscovery> {
41 let index = repo.getattr(py, "changelog")?.getattr(py, "index")?;
42 let index = repo.getattr(py, "changelog")?.getattr(py, "index")?;
42 Self::create_instance(
43 Self::create_instance(
@@ -44,7 +45,8 b' py_class!(pub class PartialDiscovery |py'
44 RefCell::new(Box::new(CorePartialDiscovery::new(
45 RefCell::new(Box::new(CorePartialDiscovery::new(
45 Index::new(py, index)?,
46 Index::new(py, index)?,
46 rev_pyiter_collect(py, &targetheads)?,
47 rev_pyiter_collect(py, &targetheads)?,
47 respectsize
48 respectsize,
49 randomize,
48 )))
50 )))
49 )
51 )
50 }
52 }
@@ -103,6 +103,9 b' class rustdiscoverytest(unittest.TestCas'
103 self.assertTrue(disco.iscomplete())
103 self.assertTrue(disco.iscomplete())
104 self.assertEqual(disco.commonheads(), {1})
104 self.assertEqual(disco.commonheads(), {1})
105
105
106 def testinitnorandom(self):
107 PartialDiscovery(self.repo(), [3], True, randomize=False)
108
106 if __name__ == '__main__':
109 if __name__ == '__main__':
107 import silenttestrunner
110 import silenttestrunner
108 silenttestrunner.main(__name__)
111 silenttestrunner.main(__name__)
General Comments 0
You need to be logged in to leave comments. Login now