def process(self,data): global fs print "Client wants to know about %s" % data.path file = self.fs.get_file(path=data.path) #if there is no such file tell the client so if not file: self.net.write(self.pb.build(packet_types.FS_ERR_PATH_NOT_FOUND, data)) return None data = packet_builder.Data(params={'oid':file.oid,'path':file.path,'num_blocks':len(file.blocks),'version':file.version,'size':file.size,'file_type':file.type,'parent':file.parent,'block_size':file.block_size}) if file.type == 0: children = [] for child in self.fs.get_children(file.oid): data_child = packet_builder.Data(params={'oid':child.oid,'path':child.path,'num_blocks':len(child.blocks),'version':child.version,'size':child.size,'file_type':child.type,'parent':child.parent,'block_size':child.block_size}) children.append(data_child) data.children = children #print data self.net.write(self.pb.build(packet_types.FS_FILE_INFO, data))
def process(self,data): global fs #client wants a file print "Client wants to delete %s" % (data.path) file = self.fs.get_file(path=data.path) #if there is no such file tell the client so if not file: data = packet_builder.Data() self.net.write(self.pb.build(packet_types.FS_ERR_PATH_NOT_FOUND, data)) return None #get current replicas of this file reps = self.fs.get_replicas(file.oid) #if the file is currently in use, tell the client so file_has_locks = self.app.serverList.file_has_locks(file.oid) if not file_has_locks: data = packet_builder.Data(params={'oid':file.oid,'version':file.version}) self.net.write(self.pb.build(packet_types.FS_ERR_LOCK_DENIED,data)) return None #delete everything we have on that file self.fs.delete_file(file.oid) #tell the client the file is gone data = packet_builder.Data(params={'oid':file.oid}) self.net.write(self.pb.build(packet_types.FS_DELETE_DONE,data)) self.net.close() if reps: #get a list of ip & ports of online servers that have such replica servers = map(self.app.serverList.get_server, reps.replicas.keys()) for server in servers: try: print "Trying %s..." % str(server) out = network_services.NetworkTransport() out.open(server[0],server[1]) out.write(self.pb.build(packet_types.FS_DELETE_OID,data)) out.close() except Exception,e: print e
def process(self, data): data = self.pb.extract_stream(self.fp) #if we are done then don't process any more incoming sync packets if data.type == packet_types.CHK_DONE: print "Sync done" return None oid = data.oid block_id = data.block_id block = self.fs.get_block(oid,block_id) #if the block has been deleted, tell the data server to delete the block too if not block: print "Block deleted" data = packet_builder.Data(params={'oid':oid,'block_id':block_id}) try: out = network_services.NetworkTransport() out.open(self.serverip,self.serverport) out.write(self.pb.build(packet_types.FS_DELETE_BLOCK,data)) out.close() except Exception,e: print e self.app.serverList.remove_address(self.serverip,self.serverport) return None
def replicate_block(self, oid, block_id, version, original_serverid, force=False): block = self.fs_db.get_block(oid, block_id) reps = self.fs_db.get_block_replicas(oid, block_id) #make sure the block we are replicating is the most current version if block.version != version: print "This version has expired! (%s) %s" % (version, block) return #replicate the file done = False while 1: if len(reps.replicas.keys()) > self.cfg.REPLICAS and not force: return None #see if we need to do any more replicas rep = self.serverList.select_new_replica_server(reps.replicas) server = self.serverList.get_server(original_serverid) if rep: # print "REPLICATE FILE: server: %s replica %s" % (server, rep) try: (ip, port, serverid) = rep data = packet_builder.Data( params={ 'oid': oid, 'block_id': block_id, 'version': version, 'serverid': original_serverid, 'ip': server[0], 'port': server[1] }) net = network_services.NetworkTransport() net.open(ip, port) net.write( self.pb.build(packet_types.FS_REPLICATE_BLOCK, data)) net.close() done = True except network_services.NetworkError, e: print "OOOOOOOOOOO: %s" % e.value #if the dataserver didn't work remove it from the active server list self.serverList.remove(serverid) print e os._exit(1) if done or not rep: break
def process(self,data): # print "FS_MODIFY_DONE: %s" % data serverid = data.serverid #release lock self.app.serverList.release_lock(data.oid,data.block_id,data.version) #update info in the database file = self.fs.get_file(oid=data.oid) block = self.fs.get_block(data.oid,data.block_id) #if the versions differ, tell the dataserver it has an invalid version if int(block.version) != int(data.version): print "Server has a different version %s != %s" % (int(file.version),int(data.version)) data = packet_builder.Data(params={'oid':file.oid,'block_id':block.block_id,'version':file.version}) self.net.write(self.pb.build(packet_types.FS_ERR_INCORRECT_VERSION,data)) return None #increment the file version and update our records block.version += 1 block.block_size = data.block_size block.size = data.block_size file.set_block(block) #add the block to the database self.fs.add_block(block, data.serverid) #tell the dataserver the new version data = packet_builder.Data(params={'oid':file.oid, 'block_id':block.block_id, 'version':block.version}) # print "Sending FS_MODIFY_ACK: %s" % data self.net.write(self.pb.build(packet_types.FS_MODIFY_ACK,data)) ds_reply = self.pb.extract_stream(self.net.sock) if ds_reply.type == packet_types.FS_VERSION_UPDATED: self.app.update_file_replicas(block.oid, block.block_id, block.version, serverid) return None
def process(self,data): print "Server %s wants a lock on oid %s:%s" % (data.serverid, data.oid, data.block_id) #check if the file is locked block_lock_success = self.app.serverList.add_lock(data.oid,data.block_id, data.version, data.serverid) data = packet_builder.Data(params={'oid':data.oid,'block_id':data.block_id,'version':data.version}) #the file is locked so tell the client better luck next time if not block_lock_success: self.net.write(self.pb.build(packet_types.FS_ERR_LOCK_DENIED,data)) else: self.net.write(self.pb.build(packet_types.FS_LOCK_OK,data)) return None
def update_file_replicas(self, oid, block_id, version, original_serverid): """Updates all replicas of oid, where the new version is in original_serverid""" reps = self.fs_db.get_block_replicas(oid, block_id) server = self.serverList.get_server(original_serverid) if not server: return reps_done = 0 for rep in reps.replicas.keys(): dest = self.serverList.get_server(rep) # print version # print reps.replicas[rep] # print dest if not dest or reps.replicas[rep] >= version: continue try: print "UPDATE REPLICA: server: %s replica %s" % (server, dest) data = packet_builder.Data( params={ 'oid': oid, 'block_id': block_id, 'version': version, 'serverid': original_serverid, 'ip': server[0], 'port': server[1] }) net = network_services.NetworkTransport() net.open(dest[0], dest[1]) net.write(self.pb.build(packet_types.FS_REPLICATE_BLOCK, data)) net.close() reps_done += 1 except network_services.NetworkError, e: print "OOOOOOOOOOO: %s" % e.value #if the dataserver didn't work remove it from the active server list self.serverList.remove(str(rep))
def process(self, data): # print "Request to delete block: (%s,%s) " % (data.oid, data.block_id) oid = data.oid block_id = data.block_id version = self.fs.get(oid, block_id) #if we have the block, delete it from the database and the file system if version: file = os.path.join(self.app.get_storage_path(oid, block_id), '__%s' % oid) self.fs.delete(oid, block_id) if os.path.exists(file): os.unlink(file) #confirm the block delete data = packet_builder.Data(params={'oid': oid, 'block_id': block_id}) self.net.write(self.pb.build(packet_types.FS_DELETE_DONE, data)) return None
def process(self,data): global fs #a dataserver is telling us that it successfully stored a replica of a file object # print "%s now has oid %s, block %s (version %s)" % (data.serverid, data.oid, data.block_id, data.version) # mon.log(1,data.oid,data.serverid, ver=data.version) serverid = data.serverid #update the new file info with version & length oid = data.oid block_id = data.block_id block = self.fs.get_block(oid, block_id) if not block: block = FSBlock(0,0,0,0,0) block.oid = data.oid block.block_id = data.block_id block.offset = data.offset block.version = data.version block.size = data.length #add the block to the database self.fs.add_block(block, data.serverid) #tell dataserver the block has been stored data = packet_builder.Data() # print "Sending ACK: %s" % data self.net.write(self.pb.build(packet_types.ACK,data)) self.app.replicate_block(block.oid, block.block_id, block.version, serverid)
def process(self, data): try: #open the file, read the data from the network and store it in the filesystem fout = open( os.path.join( self.app.get_storage_path(self.oid, self.block_id), '__%s__%s' % (self.oid, self.block_id)), "wb") # print "Trying to read %s bytes" % self.length remaining = self.length buf_size = 60000 l = 0 while remaining > 0: if buf_size > remaining: buf_size = remaining buf = self.net.read_buffered(buf_size) fout.write(buf) l += len(buf) remaining -= len(buf) fout.close() data = packet_builder.Data( params={ 'oid': self.oid, 'block_id': self.block_id, 'length': l, 'version': self.version, 'serverid': self.cfg.SERVER_ID, 'offset': self.file_offset }) #store the replica information in the data server's local database self.fs.add(self.oid, self.block_id, self.version) #tell metadata server we have the file now mds = network_services.NetworkTransport() mds.open(self.cfg.CURR_MD_IP, self.cfg.CURR_MD_PORT) mds.write(self.pb.build(packet_types.FS_BLOCK_STORED, data)) mds_reply = self.pb.extract_stream(mds.sock) mds.close() # print 'MDSERVER REPLY: %s' % mds_reply if mds_reply.type == packet_types.ACK: #tell client everything went ok self.net.write( self.pb.build(packet_types.FS_BLOCK_STORED, data)) return STATE_STORE_BLOCK_INFO() except socket.timeout: print "Socket timed out. File transfer failed for %s:%s." % ( self.oid, self.block_id) self.rollback(fout) #TODO: tell metadata that the client crashed on this operation return None except IOError: print "Error while creating file __%s__%s." % (self.oid, self.block_id) data = Data() data.oid = self.oid data.block_id = self.block_id #Notify client there was an error creating this file self.net.write(pb.build(packet_types.FS_ERR_STORE, data)) return None
def process(self, data): try: #open the file, read the data from the network and store it in the filesystem if self.offset == -1: fout = open( os.path.join( self.app.get_storage_path(self.oid, self.block_id), '__%s__%s' % (self.oid, self.block_id)), "ab+") else: fout = open( os.path.join( self.app.get_storage_path(self.oid, self.block_id), '__%s__%s' % (self.oid, self.block_id)), "r+w") fout.seek(self.offset) # print "Trying to get and write %s bytes at %s" % (self.length, self.offset) l = 0 remaining = self.length buf_size = 64000 while remaining > 0: if buf_size > remaining: buf_size = remaining buf = self.net.read_buffered(buf_size) l += len(buf) remaining -= len(buf) fout.write(buf) fout.close() #get the new size of the block block_size = os.path.getsize( os.path.join( self.app.get_storage_path(self.oid, self.block_id), '__%s__%s' % (self.oid, self.block_id))) # print "Update block: %s:%s" % (self.oid, self.block_id) data = packet_builder.Data( params={ 'oid': self.oid, 'block_id': self.block_id, 'length': l, 'version': self.version, 'serverid': self.cfg.SERVER_ID, 'offset': self.offset, 'block_size': block_size }) #tell metadata server we succesfully modified the block mds = network_services.NetworkTransport() mds.open(self.cfg.CURR_MD_IP, self.cfg.CURR_MD_PORT) mds.write(self.pb.build(packet_types.FS_MODIFY_DONE, data)) mds_reply = self.pb.extract_stream(mds.sock) print 'MDSERVER REPLY: %s' % mds_reply if mds_reply.type == packet_types.FS_MODIFY_ACK: #store the replica information in the data server's local database self.fs.add(mds_reply.oid, mds_reply.block_id, mds_reply.version) mds.write( self.pb.build(packet_types.FS_VERSION_UPDATED, mds_reply)) data.version = mds_reply.version #tell client everything went ok self.net.write(self.pb.build(packet_types.FS_MODIFY_DONE, data)) else: self.rollback(None) mds.close() return STATE_STORE_BLOCK_INFO() except socket.timeout: print "Socket timed out. File transfer failed for %s." % self.oid self.rollback(fout) return None except IOError: print "Error while creating file __%s." % self.oid data = Data() data.oid = self.oid #Notify client there was an error creating this file self.net.write(pb.build(packet_types.FS_ERR_STORE, data)) self.rollback(fout) return None
def process(self, data): # print "Request to modify block: %s:%s version %s (%s:%s)" % (self.oid, self.block_id, self.version, self.block_offset, self.length) oid = self.oid block_id = self.block_id stored_version = self.fs.get(oid, block_id) #check if we have the file and if not tell the client so if not stored_version: d = packet_builder.Data(params={ 'oid': oid, 'block_id': self.block_id, 'version': self.version }) self.net.write( self.pb.build(packet_types.FS_ERR_BLOCK_NOT_FOUND, d)) return None #check if we have the correct version and if not tell the client which version we have if int(stored_version) != int(self.version): print "We have a different version! (%s vs %s)" % (stored_version, data.version) d = packet_builder.Data(params={ 'oid': oid, 'block_id': block_id, 'version': self.version }) self.net.write( self.pb.build(packet_types.FS_ERR_INCORRECT_VERSION, d)) return None #try to get a lock for this block from the metadata server # print "Getting lock..." if not self.app.get_block_lock(self.oid, self.block_id, self.version): d = packet_builder.Data(params={ 'oid': oid, 'block_id': self.block_id, 'version': self.version }) self.net.write(self.pb.build(packet_types.FS_ERR_LOCK_DENIED, d)) return None #TODO: release locks after each failure #get the file length try: file = os.path.join(self.app.get_storage_path(oid, block_id), '__%s__%s' % (oid, block_id)) file_size = os.path.getsize(file) except OSError: #if we didn't find a file tell the client d = packet_builder.Data(params={ 'oid': oid, 'version': self.version }) self.net.write(self.pb.build(packet_types.FS_ERR_OID_NOT_FOUND, d)) #and update our database self.fs.delete(oid) return None offset = self.block_offset #check that if the client is not appending it's not trying to write outside the file bounds if offset != -1: # print "Block size: %s, block offset: %s" % (file_size, offset) if offset > file_size: data = packet_builder.Data( params={ 'oid': oid, 'block_id': self.block_id, 'version': self.version, 'serverid': self.cfg.SERVER_ID, }) self.net.write( self.pb.build(packet_types.FS_ERR_BUFFER_OUT_OF_RANGE, data)) return None return STATE_MODIFY_BLOCK(self.oid, self.block_id, self.block_offset, self.length, self.version)
def process(self, data): oid = data.oid block_id = data.block_id version = self.fs.get(oid, block_id) # print "Client wants %s:%s (version %s)" % (oid, block_id, data.version) #check if we have the file and if not tell the client so if not version: print "Block not found: (%s,%s)" % (oid, block_id) d = packet_builder.Data(params={ 'oid': oid, 'block_id': block_id, 'version': data.version }) self.net.write( self.pb.build(packet_types.FS_ERR_BLOCK_NOT_FOUND, d)) return None #check if we have the correct version and if not tell the client which version we have if int(version) != int(data.version): d = packet_builder.Data(params={ 'oid': oid, 'block_id': block_id, 'version': version }) print "Incorrect version: I have (%s) and client wants (%s)" % ( version, data.version) self.net.write( self.pb.build(packet_types.FS_ERR_INCORRECT_VERSION, d)) return None #get the file length try: file = os.path.join(self.app.get_storage_path(oid, block_id), '__%s__%s' % (oid, block_id)) length = os.path.getsize(file) except OSError: #if we didn't find a file tell the client d = packet_builder.Data(params={ 'oid': oid, 'block_id': block_id, 'version': data.version }) self.net.write( self.pb.build(packet_types.FS_ERR_BLOCK_NOT_FOUND, d)) #and update our database self.fs.delete(oid) return None try: #confirm the file transfer data = packet_builder.Data( params={ 'oid': oid, 'block_id': block_id, 'version': version, 'length': length }) self.net.write(self.pb.build(packet_types.FS_REQUEST_OK, data)) #send the file! f = open(file, 'rb') while 1: buf = f.read(64000) if not buf: break self.net.write(buf) f.close() except socket.timeout: print "Socket timed out. File transfer failed for %s:%s." % ( oid, block_id) except IOError: print "Something went wrong while reading %s:%s" % (oid, block_id) return None
def process(self, data): #check if there are any active dataservers where we can store this file l = len(self.app.serverList.get()) #if there are none, tell the client if not l: self.net.write(self.pb.build(packet_types.FS_ERR_NODATASERVERS, None)) return None #check if the file already exists file = self.fs.get_file(path=data.path) if file: self.net.write(self.pb.build(packet_types.FS_ERR_CREATE, None)) return None type = data.file_type version = 1 #this is the first revision of the file if type == 1: #it's a file #set the number of replicas for this file desired_replicas = data.replicas if not desired_replicas: desired_replicas = self.cfg.REPLICAS #set the block size for this file block_size = data.block_size if block_size == 0: block_size = self.cfg.BLOCK_SIZE elif type == 0: #it's a folder block_size = 0 #store the file in our database (path,name) = os.path.split(data.path) f = FSObject(0,1,name,0,type,0, block_size) try: oid = self.fs.insert_file(path,f) # if this exception occurs at this point, it means the file doesn't have one or more parent directories. except FileSystemError: dirs = [] tmp = (path,None) while 1: tmp = os.path.split(tmp[0]) dirs.insert(0, tmp) if tmp[0] == '/': break # lets start trying to create those parent directories! print "-----------" print dirs print "-----------" for i in dirs: # check if directory already exists tmp = i[0] + '/' + i[1] if self.fs.get_file(path=tmp): print str(tmp) + " exists. Continue.................................." continue # create the directory print str(tmp) + " is being created................" x = FSObject(0,1,i[1],0,0,0,0) self.fs.insert_file(i[0],x) # store the file oid = self.fs.insert_file(path,f) try: if type == 1: #it's a file #set the number of replicas for this file desired_replicas = data.replicas if not desired_replicas: desired_replicas = self.cfg.REPLICAS #set the block size for this file block_size = data.block_size if not block_size: block_size = self.cfg.BLOCK_SIZE (ip,port,serverid) = self.app.serverList.select_dataserver(oid) data = packet_builder.Data(params={'ip':ip,'port':port,'serverid':serverid,'oid':oid,'version':version,'block_size':block_size,'replicas':desired_replicas}) self.net.write(self.pb.build(packet_types.FS_CREATE_OK, data)) else: #it's a folder desired_replicas = 0 #no replicas for a folder block_size = 0 data = packet_builder.Data(params={'oid':oid,'length':0,'version':version,'serverid':0}) self.net.write(self.pb.build(packet_types.FS_NODE_CREATED,data)) except fs_db.FileSystemError: self.net.write(self.pb.build(packet_types.FS_ERR_CREATE, None)) return None
def process(self,data): global fs #client wants a file print "Client requests %s" % (data.path) file = self.fs.get_file(path=data.path) #if there is no such file tell the client so if not file: data = packet_builder.Data() self.net.write(self.pb.build(packet_types.FS_ERR_PATH_NOT_FOUND, data)) return None #get the file's blocks and replicas blocks = self.fs.get_blocks(file.oid,byte_start=0,byte_end=0) replicas = self.fs.get_file_replicas(file.oid) #get an online dataserver where this file is stored block_replicas = self.app.serverList.select_blocks_replicas(file.blocks, replicas) #if the file size > 0 but there are no online servers that can serve all blocks if file.size > 0 and not block_replicas: data = packet_builder.Data() self.net.write(self.pb.build(packet_types.FS_ERR_NO_REPLICAS,data)) return None #tell the client where it can get the file data = packet_builder.Data(params={'oid':file.oid,'file_size':file.size, 'version':file.version,'block_size':file.block_size, 'file_type':file.type}) #build the list of blocks and servers data.blocks = [] for block_id in file.blocks.keys(): block = packet_builder.Data() block.block_id = block_id block.version = blocks[block_id].version block.block_size = blocks[block_id].size block.offset = blocks[block_id].offset block.ip = block_replicas[block_id][0] block.port = block_replicas[block_id][1] block.serverid = block_replicas[block_id][2] data.blocks.append(block) #send the client the ok signal and a list of servers where it can get each block self.net.write(self.pb.build(packet_types.FS_GET_OK,data)) # ds_list_lock.acquire() # replicate_further = serverList.oid_used(file.oid) # ds_list_lock.release() # if replicate_further: # serverid = get_current_replica_server(file.oid,file.version) # replicate_file(file.oid, file.version, serverid,force=True) return None