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