2008-07-12 21:26:22 +00:00
#!/usr/bin/env python
2010-03-03 23:19:02 +00:00
# WARNING. There is a bug in this script so that it does not simulate the actual Tahoe Two server selection algorithm that it was intended to simulate. See http://allmydata.org/trac/tahoe-lafs/ticket/302 (stop permuting peerlist, use SI as offset into ring instead?)
2008-07-12 21:26:22 +00:00
import random
2008-07-21 21:11:06 +00:00
SERVER_CAPACITY = 10 * * 12
2008-07-12 21:26:22 +00:00
class Server :
def __init__ ( self ) :
self . si = random . randrange ( 0 , 2 * * 31 )
self . used = 0
2008-07-21 21:11:06 +00:00
self . max = SERVER_CAPACITY
2008-07-12 21:26:22 +00:00
self . full_at_tick = None
def __repr__ ( self ) :
if self . full_at_tick is not None :
return " < %s %s full at %d > " % ( self . __class__ . __name__ , self . si , self . full_at_tick )
else :
return " < %s %s > " % ( self . __class__ . __name__ , self . si )
2008-07-21 21:11:06 +00:00
SERVERS = 4
2008-07-12 21:26:22 +00:00
K = 3
N = 10
2008-07-12 23:54:29 +00:00
def make_up_a_file_size ( ) :
return ( 2 * * random . randrange ( 8 , 31 ) )
2008-07-12 21:26:22 +00:00
def go ( permutedpeerlist ) :
servers = [ Server ( ) for x in range ( SERVERS ) ]
servers . sort ( cmp = lambda x , y : cmp ( x . si , y . si ) )
2008-07-21 21:11:06 +00:00
doubled_up_shares = 0
2008-07-12 21:26:22 +00:00
tick = 0
fullservers = 0
while True :
2008-07-12 23:54:29 +00:00
nextsharesize = make_up_a_file_size ( ) / K
2008-07-12 21:26:22 +00:00
if permutedpeerlist :
random . shuffle ( servers )
else :
# rotate a random number
rot = random . randrange ( 0 , len ( servers ) )
servers = servers [ rot : ] + servers [ : rot ]
i = 0
2008-07-21 21:11:06 +00:00
wrapped = False
2008-07-12 23:54:29 +00:00
sharestoput = N
2008-07-12 21:26:22 +00:00
while sharestoput :
server = servers [ i ]
if server . used + nextsharesize < server . max :
server . used + = nextsharesize
sharestoput - = 1
2008-07-21 21:11:06 +00:00
if wrapped :
doubled_up_shares + = 1
2008-07-12 21:26:22 +00:00
else :
if server . full_at_tick is None :
server . full_at_tick = tick
fullservers + = 1
if fullservers == len ( servers ) :
# print "Couldn't place share -- all servers full. Stopping."
2008-07-21 21:11:06 +00:00
return ( servers , doubled_up_shares )
2008-07-12 21:26:22 +00:00
2008-07-21 21:11:06 +00:00
i + = 1
if i == len ( servers ) :
wrapped = True
i = 0
2008-07-12 21:26:22 +00:00
tick + = 1
2008-07-12 22:37:27 +00:00
def div_ceil ( n , d ) :
"""
The smallest integer k such that k * d > = n .
"""
return ( n / d ) + ( n % d != 0 )
DESIRED_COLUMNS = 70
2008-07-12 23:54:29 +00:00
START_FILES = 137000
STOP_FILES = 144000
2008-07-12 21:26:22 +00:00
def test ( permutedpeerlist , iters ) :
2008-07-12 22:37:27 +00:00
# The i'th element of the filledat list is how many servers got full when the i'th file was uploaded.
filledat = [ ]
2008-07-12 21:26:22 +00:00
for test in range ( iters ) :
2008-07-21 21:11:06 +00:00
( servers , doubled_up_shares ) = go ( permutedpeerlist )
print " doubled_up_shares: " , doubled_up_shares
2008-07-12 21:26:22 +00:00
for server in servers :
2008-07-12 22:37:27 +00:00
fidx = server . full_at_tick
filledat . extend ( [ 0 ] * ( fidx - len ( filledat ) + 1 ) )
2008-07-12 21:26:22 +00:00
filledat [ fidx ] + = 1
2008-07-12 22:37:27 +00:00
startfiles = 0
while filledat [ startfiles ] == 0 :
startfiles + = 1
filespercolumn = div_ceil ( len ( filledat ) - startfiles , ( DESIRED_COLUMNS - 3 ) )
2008-07-12 23:54:29 +00:00
# to make comparisons between runs line up:
2008-07-21 21:11:06 +00:00
# startfiles = START_FILES
# filespercolumn = div_ceil(STOP_FILES - startfiles, (DESIRED_COLUMNS - 3))
2008-07-12 23:54:29 +00:00
2008-07-12 22:37:27 +00:00
# The i'th element of the compressedfilledat list is how many servers got full when the filespercolumn files starting at startfiles + i were uploaded.
compressedfilledat = [ ]
idx = startfiles
while idx < len ( filledat ) :
compressedfilledat . append ( 0 )
for i in range ( filespercolumn ) :
compressedfilledat [ - 1 ] + = filledat [ idx ]
idx + = 1
if idx > = len ( filledat ) :
break
# The i'th element of the fullat list is how many servers were full by the tick numbered startfiles + i * filespercolumn (on average).
fullat = [ 0 ] * len ( compressedfilledat )
for idx , num in enumerate ( compressedfilledat ) :
2008-07-12 21:26:22 +00:00
for fidx in range ( idx , len ( fullat ) ) :
fullat [ fidx ] + = num
for idx in range ( len ( fullat ) ) :
fullat [ idx ] = fullat [ idx ] / float ( iters )
# Now print it out as an ascii art graph.
import sys
for serversfull in range ( 40 , 0 , - 1 ) :
2008-07-12 22:37:27 +00:00
sys . stdout . write ( " %2d " % serversfull )
2008-07-12 21:26:22 +00:00
for numfull in fullat :
if int ( numfull ) == serversfull :
sys . stdout . write ( " * " )
else :
sys . stdout . write ( " " )
sys . stdout . write ( " \n " )
sys . stdout . write ( " ^-- servers full \n " )
idx = 0
while idx < len ( fullat ) :
2008-07-12 22:37:27 +00:00
nextmark = " %d --^ " % ( startfiles + idx * filespercolumn )
sys . stdout . write ( nextmark )
idx + = len ( nextmark )
2008-07-12 21:26:22 +00:00
sys . stdout . write ( " \n files uploaded --> \n " )
if __name__ == " __main__ " :
import sys
iters = 16
for arg in sys . argv :
if arg . startswith ( " --iters= " ) :
iters = int ( arg [ 8 : ] )
if " --permute " in sys . argv :
print " doing permuted peerlist, iterations: %d " % iters
test ( True , iters )
else :
print " doing simple ring, iterations: %d " % iters
test ( False , iters )