104
107
tree. Not hardlinking the working tree, because there are no working
110
from bzrlib.benchmarks.tree_creator.heavily_merged import (
111
HeavilyMergedTreeCreator,
107
113
creator = HeavilyMergedTreeCreator(self, link_bzr=hardlink)
108
114
return creator.create(root=directory_name)
111
class TreeCreator(object):
112
"""Just a basic class which is used to create various test trees"""
116
def __init__(self, test, tree_name,
120
"""Instantiate a new creator object, supply the id of the tree"""
122
self._cache_root = TreeCreator.CACHE_ROOT
124
self._tree_name = tree_name
125
self._link_bzr = link_bzr
126
self._link_working = link_working
127
self._hot_cache = hot_cache
128
if not osutils.hardlinks_good():
129
self._link_working = self._link_bzr = False
131
def is_caching_enabled(self):
132
"""Will we try to cache the tree we create?"""
133
return self._cache_root is not None
136
"""Is this tree already cached?"""
137
cache_dir = self._get_cache_dir()
138
if cache_dir is None:
140
return os.path.exists(cache_dir)
142
def disable_cache(self):
143
"""Do not use the cache"""
144
self._cache_root = None
146
def ensure_cached(self):
147
"""If caching, make sure the cached copy exists"""
148
cache_dir = self._get_cache_dir()
149
if cache_dir is None:
152
if not self.is_cached():
153
self._create_tree(root=cache_dir, in_cache=True)
155
def create(self, root):
156
"""Create a new tree at 'root'.
158
:return: A WorkingTree object.
160
cache_dir = self._get_cache_dir()
161
if cache_dir is None:
163
return self._create_tree(root, in_cache=False)
167
return self._clone_cached_tree(root)
169
def _get_cache_dir(self):
170
"""Get the directory to use for caching this tree
172
:return: The path to use for caching. If None, caching is disabled
174
if self._cache_root is None:
176
return osutils.pathjoin(self._cache_root, self._tree_name)
178
def _create_tree(self, root, in_cache=False):
179
"""Create the desired tree in the given location.
181
Children should override this function to provide the actual creation
182
of the desired tree. This will be called by 'create()'. If it is
183
building a tree in the cache, before copying it to the real target,
184
it will pass in_cache=True
186
raise NotImplemented(self._create_tree)
188
def _clone_cached_tree(self, dest):
189
"""Copy the contents of the cached dir into the destination
190
Optionally hardlink certain pieces of the tree.
192
This is just meant as a helper function for child classes
194
:param dest: The destination to copy things to
196
# We use shutil.copyfile so that we don't copy permissions
197
# because most of our source trees are marked readonly to
198
# prevent modifying in the case of hardlinks
199
handlers = {'file':shutil.copyfile}
200
if osutils.hardlinks_good():
201
if self._link_working:
203
handlers = {'file':os.link}
205
# Don't hardlink files inside bzr
206
def file_handler(source, dest):
207
if '.bzr/' in source:
208
shutil.copyfile(source, dest)
210
os.link(source, dest)
211
handlers = {'file':file_handler}
213
# Only link files inside .bzr/
214
def file_handler(source, dest):
215
if '.bzr/' in source:
216
os.link(source, dest)
218
shutil.copyfile(source, dest)
219
handlers = {'file':file_handler}
221
source = self._get_cache_dir()
222
osutils.copy_tree(source, dest, handlers=handlers)
223
tree = workingtree.WorkingTree.open(dest)
227
# tree._hashcache.scan() just checks and removes
228
# entries that are out of date
229
# we need to actually store new ones
230
for path, ie in tree.inventory.iter_entries_by_dir():
231
tree.get_file_sha1(ie.file_id, path)
234
# If we didn't iterate the tree, the hash cache is technically
235
# invalid, and it would be better to remove it, but there is
236
# no public api for that.
239
def _protect_files(self, root):
240
"""Chmod all files underneath 'root' to prevent writing
242
This is a helper function for child classes.
244
:param root: The base directory to modify
246
for dirinfo, entries in osutils.walkdirs(root):
247
for relpath, name, kind, st, abspath in entries:
249
os.chmod(abspath, 0440)
252
class KernelLikeTreeCreator(TreeCreator):
253
"""Create a basic tree with ~10k unversioned files"""
255
def __init__(self, test, link_working=False, url=None):
256
super(KernelLikeTreeCreator, self).__init__(test,
257
tree_name='kernel_like_tree',
258
link_working=link_working,
263
def create(self, root):
264
"""Create all the kernel files in the given location.
266
This is overloaded for compatibility reasons.
268
if self._url is not None:
269
b = bzrdir.BzrDir.create_branch_convenience(self._url)
270
d = bzrdir.BzrDir.create(root)
271
bzrlib.branch.BranchReferenceFormat().initialize(d, b)
272
tree = d.create_workingtree()
274
tree = bzrdir.BzrDir.create_standalone_workingtree(root)
276
if not self._link_working or not self.is_caching_enabled():
277
# Turns out that 'shutil.copytree()' is no faster than
278
# just creating them. Probably the python overhead.
279
# Plain _make_kernel_files takes 3-5s
281
# using hardlinks takes < 1s.
282
self._create_tree(root=root, in_cache=False)
286
cache_dir = self._get_cache_dir()
287
osutils.copy_tree(cache_dir, root,
288
handlers={'file':os.link})
291
def _create_tree(self, root, in_cache=False):
292
# a kernel tree has ~10000 and 500 directory, with most files around
294
# we simulate this by three levels of dirs named 0-7, givin 512 dirs,
297
for outer in range(8):
298
files.append("%s/" % outer)
299
for middle in range(8):
300
files.append("%s/%s/" % (outer, middle))
301
for inner in range(8):
302
prefix = "%s/%s/%s/" % (outer, middle, inner)
304
files.extend([prefix + str(foo) for foo in range(20)])
305
cwd = osutils.getcwd()
307
self._test.build_tree(files)
310
self._protect_files(root)
313
class KernelLikeAddedTreeCreator(TreeCreator):
315
def __init__(self, test, link_working=False, hot_cache=True):
316
super(KernelLikeAddedTreeCreator, self).__init__(test,
317
tree_name='kernel_like_added_tree',
318
link_working=link_working,
322
def _create_tree(self, root, in_cache=False):
323
"""Create a kernel-like tree with the all files added
325
:param root: The root directory to create the files
326
:param in_cache: Is this being created in the cache dir?
328
kernel_creator = KernelLikeTreeCreator(self._test,
329
link_working=in_cache)
330
tree = kernel_creator.create(root=root)
332
# Add everything to it
335
add.smart_add_tree(tree, [root], recurse=True, save=True)
337
self._protect_files(root+'/.bzr')
343
class KernelLikeCommittedTreeCreator(TreeCreator):
344
"""Create a tree with ~10K files, and a single commit adding all of them"""
346
def __init__(self, test, link_working=False, link_bzr=False,
348
super(KernelLikeCommittedTreeCreator, self).__init__(test,
349
tree_name='kernel_like_committed_tree',
350
link_working=link_working,
354
def _create_tree(self, root, in_cache=False):
355
"""Create a kernel-like tree with all files committed
357
:param root: The root directory to create the files
358
:param in_cache: Is this being created in the cache dir?
360
kernel_creator = KernelLikeAddedTreeCreator(self._test,
361
link_working=in_cache,
362
hot_cache=(not in_cache))
363
tree = kernel_creator.create(root=root)
364
tree.commit('first post', rev_id='r1')
367
self._protect_files(root+'/.bzr')
371
class SimpleManyCommitTreeCreator(TreeCreator):
372
"""Create an empty tree with lots of commits"""
374
def __init__(self, test, link_bzr=False):
375
super(SimpleManyCommitTreeCreator, self).__init__(test,
376
tree_name='many_commit_tree',
381
def _create_tree(self, root, in_cache=False):
382
tree = bzrdir.BzrDir.create_standalone_workingtree(root)
385
for i in xrange(1000):
386
tree.commit('no-changes commit %d' % i)
390
self._protect_files(root+'/.bzr')
395
class HeavilyMergedTreeCreator(TreeCreator):
396
"""Create a tree in which almost every commit is a merge.
398
No file changes are included. This produces two trees,
399
one of which is returned. Except for the first commit, every
400
commit in its revision-history is a merge of another commit in the other
402
Not hardlinking the working tree, because there are no working tree files.
405
def __init__(self, test, link_bzr=True):
406
super(HeavilyMergedTreeCreator, self).__init__(test,
407
tree_name='heavily_merged_tree',
412
def _create_tree(self, root, in_cache=False):
415
except (IOError, OSError), e:
416
if e.errno not in (errno.EEXIST,):
419
tree = bzrdir.BzrDir.create_standalone_workingtree(root)
422
tree2 = tree.bzrdir.sprout(root + '/tree2').open_workingtree()
425
for i in xrange(250):
426
revision_id = tree.commit('no-changes commit %d-a' % i)
427
tree2.branch.fetch(tree.branch, revision_id)
428
tree2.set_pending_merges([revision_id])
429
revision_id = tree2.commit('no-changes commit %d-b' % i)
430
tree.branch.fetch(tree2.branch, revision_id)
431
tree.set_pending_merges([revision_id])
432
tree.set_pending_merges([])
438
self._protect_files(root+'/.bzr')
442
117
def test_suite():
443
118
"""Build and return a TestSuite which contains benchmark tests only."""
444
119
testmod_names = [ \