maketree.py 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. #! /usr/bin/python2.2
  2. # Copyright (C) 2002 by Martin Pool <mbp@samba.org>
  3. # This program is free software; you can redistribute it and/or modify
  4. # it under the terms of the GNU General Public License version
  5. # 2 as published by the Free Software Foundation.
  6. #
  7. # This program is distributed in the hope that it will be useful, but
  8. # WITHOUT ANY WARRANTY; without even the implied warranty of
  9. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  10. # Lesser General Public License for more details.
  11. #
  12. # You should have received a copy of the GNU Lesser General Public
  13. # License along with this program; if not, write to the Free Software
  14. # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. # Populate a tree with pseudo-randomly distributed files to test
  16. # rsync.
  17. from __future__ import generators
  18. import random, string, os, os.path
  19. nfiles = 10000
  20. depth = 5
  21. n_children = 20
  22. n_files = 20
  23. n_symlinks = 10
  24. name_chars = string.digits + string.letters
  25. abuffer = 'a' * 1024
  26. def random_name_chars():
  27. a = ""
  28. for i in range(10):
  29. a = a + random.choice(name_chars)
  30. return a
  31. def generate_names():
  32. n = 0
  33. while 1:
  34. yield "%05d_%s" % (n, random_name_chars())
  35. n += 1
  36. class TreeBuilder:
  37. def __init__(self):
  38. self.n_children = 20
  39. self.n_files = 100
  40. self.total_entries = 100000 # long(1e8)
  41. self.actual_size = 0
  42. self.name_gen = generate_names()
  43. self.all_files = []
  44. self.all_dirs = []
  45. self.all_symlinks = []
  46. def random_size(self):
  47. return random.lognormvariate(4, 4)
  48. def random_symlink_target(self):
  49. what = random.choice(['directory', 'file', 'symlink', 'none'])
  50. try:
  51. if what == 'directory':
  52. return random.choice(self.all_dirs)
  53. elif what == 'file':
  54. return random.choice(self.all_files)
  55. elif what == 'symlink':
  56. return random.choice(self.all_symlinks)
  57. elif what == 'none':
  58. return self.name_gen.next()
  59. except IndexError:
  60. return self.name_gen.next()
  61. def can_continue(self):
  62. self.total_entries -= 1
  63. return self.total_entries > 0
  64. def build_tree(self, prefix, depth):
  65. """Generate a breadth-first tree"""
  66. for count, function in [[n_files, self.make_file],
  67. [n_children, self.make_child_recurse],
  68. [n_symlinks, self.make_symlink]]:
  69. for i in range(count):
  70. if not self.can_continue():
  71. return
  72. name = os.path.join(prefix, self.name_gen.next())
  73. function(name, depth)
  74. def print_summary(self):
  75. print "total bytes: %d" % self.actual_size
  76. def make_child_recurse(self, dname, depth):
  77. if depth > 1:
  78. self.make_dir(dname)
  79. self.build_tree(dname, depth-1)
  80. def make_dir(self, dname, depth='ignore'):
  81. print "%s/" % (dname)
  82. os.mkdir(dname)
  83. self.all_dirs.append(dname)
  84. def make_symlink(self, lname, depth='ignore'):
  85. print "%s -> %s" % (lname, self.random_symlink_target())
  86. def make_file(self, fname, depth='ignore'):
  87. size = long(self.random_size())
  88. print "%-70s %d" % (fname, size)
  89. f = open(fname, 'w')
  90. f.truncate(size)
  91. self.fill_file(f, size)
  92. self.all_files.append(fname)
  93. self.actual_size += size
  94. def fill_file(self, f, size):
  95. while size > 0:
  96. f.write(abuffer[:size])
  97. size -= len(abuffer)
  98. tb = TreeBuilder()
  99. tb.build_tree('/tmp/foo', 3)
  100. tb.print_summary()