00001 __copyright__ = """
00002 Copyright 2008 Henryk Modzelewski
00003 """
00004 __license__ = """
00005 This file is part of SLIMpy .
00006
00007 SLIMpy is free software: you can redistribute it and/or modify
00008 it under the terms of the GNU Lesser General Public License as published by
00009 the Free Software Foundation, either version 3 of the License, or
00010 (at your option) any later version.
00011
00012 SLIMpy is distributed in the hope that it will be useful,
00013 but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00015 GNU Lesser General Public License for more details.
00016
00017 You should have received a copy of the GNU Lesser General Public License
00018 along with SLIMpy . If not, see <http://www.gnu.org/licenses/>.
00019 """
00020
00021 import random
00022
00023 def PrintSortedHash(name,table):
00024 '''
00025 Prints hash elements ordered by sorted keys.
00026 '''
00027 print name+':'
00028 keys=table.keys()
00029 keys.sort()
00030 for key in keys:
00031 print '\t',key,table[key]
00032
00033 def even_dist(nodes,files,VERBOSE=False):
00034 '''
00035 DESCRIPTION:
00036 even_dist finds unique node to file assignment
00037 and attempts to minimize the number of necessary
00038 copy operations.
00039
00040 TAKES:
00041 nodes: list of nodes
00042 files: list of data container objects
00043 RETURNS:
00044 the tuple ordered as files with either:
00045 target - if file is at the right position
00046 (source,target) - if file is to be copied
00047 from source to target
00048 '''
00049 if VERBOSE: print '\n* Into even_dist'
00050
00051 nfiles=len(files)
00052 assert(nfiles==len(nodes))
00053 unodes = list(set(nodes))
00054 unodes.sort()
00055 unodes = tuple(unodes)
00056 unlen = len(unodes)
00057 if VERBOSE: print 'unodes: ',unlen,unodes
00058
00059 ncount = {}
00060 for node in unodes: ncount[node] = nodes.count(node)
00061 npool = {}
00062 fpool = {}
00063 for file in files:
00064 for node in file.nodenames:
00065 if npool.has_key(node): npool[node].append(file.data)
00066 else: npool[node]=[file.data]
00067 if fpool.has_key(file.data): fpool[file.data].append(node)
00068 else: fpool[file.data]=[node]
00069 for key in npool: npool[key].sort()
00070 for key in fpool: fpool[key].sort()
00071 if VERBOSE:
00072 PrintSortedHash('ncount',ncount)
00073 PrintSortedHash('npool',npool)
00074 PrintSortedHash('fpool',fpool)
00075
00076 copy = {}
00077 ndone = {}
00078 for elm in unodes: ndone[elm]=[]
00079
00080
00081 if VERBOSE: print '\n* Finding unique files'
00082 for i in xrange(unlen):
00083 if not npool.has_key(unodes[i]): continue
00084 dummy = set(npool[unodes[i]])
00085 for j in xrange(unlen):
00086 if j!=i and npool.has_key(unodes[j]): dummy=dummy-set(npool[unodes[j]])
00087 dummy = list(dummy)
00088 dummy = dummy[:ncount[unodes[i]]]
00089 for elm in dummy:
00090 ndone[unodes[i]].append(elm)
00091 ncount[unodes[i]] = ncount[unodes[i]] - 1
00092 copy[elm]=(None,unodes[i])
00093 for key in npool:
00094 if npool[key].count(elm): npool[key].remove(elm)
00095 del fpool[elm]
00096 if VERBOSE:
00097 PrintSortedHash('ncount',ncount)
00098 PrintSortedHash('npool',npool)
00099 PrintSortedHash('fpool',fpool)
00100 PrintSortedHash('ndone',ndone)
00101 PrintSortedHash('copy',copy)
00102
00103
00104 if VERBOSE: print '\n* Finding files already on the owner node'
00105 for i in xrange(unlen):
00106 if not npool.has_key(unodes[i]): continue
00107 dummy = npool[unodes[i]][:ncount[unodes[i]]]
00108 for elm in dummy:
00109 ndone[unodes[i]].append(elm)
00110 ncount[unodes[i]] = ncount[unodes[i]] - 1
00111 copy[elm]=(None,unodes[i])
00112 for key in npool:
00113 if npool[key].count(elm): npool[key].remove(elm)
00114 del fpool[elm]
00115 ndone[unodes[i]].sort()
00116 if VERBOSE:
00117 PrintSortedHash('ncount',ncount)
00118 PrintSortedHash('npool',npool)
00119 PrintSortedHash('fpool',fpool)
00120 PrintSortedHash('ndone',ndone)
00121 PrintSortedHash('copy',copy)
00122
00123 if VERBOSE: print '\n* Find files to be copied'
00124 for i in xrange(unlen):
00125 while ncount[unodes[i]] > 0:
00126 fdummies = fpool.keys()
00127 fdummy = random.sample(fdummies,1)[0]
00128 ndummies = fpool[fdummy]
00129 ndummy = random.sample(ndummies,1)[0]
00130 ndone[unodes[i]].append(fdummy)
00131 ncount[unodes[i]]=ncount[unodes[i]]-1
00132 copy[fdummy]=(ndummy,unodes[i])
00133 for key in npool:
00134 if npool[key].count(fdummy): npool[key].remove(fdummy)
00135 del fpool[fdummy]
00136 if VERBOSE:
00137 PrintSortedHash('ncount',ncount)
00138 PrintSortedHash('npool',npool)
00139 PrintSortedHash('fpool',fpool)
00140 PrintSortedHash('ndone',ndone)
00141 PrintSortedHash('copy',copy)
00142
00143
00144 if VERBOSE: print '\n* Check uniqueness'
00145 for i in xrange(unlen):
00146 dummy = set(ndone[unodes[i]])
00147 dummies = set()
00148 for j in xrange(unlen):
00149 if j!=i: dummies=dummies|set(ndone[unodes[j]])
00150 unique = dummies&dummy
00151 if len(unique) > 0: raise 'Nonounique File Assignment for', (unodes[i],list(unique))
00152
00153
00154 if VERBOSE: print '\n* Check Existence'
00155 for idx in xrange(nfiles):
00156 file = files[idx].data
00157 if not copy.has_key(file): raise 'Unresolved File@Node Assignment', file
00158 if copy[file][0]:
00159
00160 if list(files[idx].nodenames).count(copy[file][0]):
00161 if VERBOSE: print file, '->', copy[file], ': source OK'
00162 else:
00163 if VERBOSE: print file, '->', copy[file], ': source error'
00164 raise 'Nonexistent File at the source', (file,copy[file])
00165
00166 if list(files[idx].nodenames).count(copy[file][1]):
00167 if VERBOSE: print file, '->', copy[file], ': target error'
00168 raise 'Obsolete File copy', (file,copy[file])
00169 else:
00170 if VERBOSE: print file, '->', copy[file], ': target OK'
00171 else:
00172
00173 if list(files[idx].nodenames).count(copy[file][1]):
00174 if VERBOSE: print file, '->', copy[file], ': target OK'
00175 else:
00176 if VERBOSE: print file, '->', copy[file], ': target error'
00177 raise 'Nonexistent File at the target', (file,copy[file])
00178
00179
00180 if VERBOSE: print '\n* Make result:'
00181 result = []
00182 for idx in xrange(nfiles):
00183 file = files[idx].data
00184 if copy[file][0]: result.append(copy[file])
00185 else: result.append(copy[file][1])
00186
00187 if VERBOSE: print '\n* Done even_dist\n'
00188 return tuple(result)
00189