From 248d33544fa816ebedaeed99a1fb8551639c05f3 Mon Sep 17 00:00:00 2001 From: Miguel Jara Date: Thu, 30 Nov 2023 16:42:40 -0500 Subject: [PATCH 1/4] Add RAID 4 functionality --- block.py | 70 ++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 56 insertions(+), 14 deletions(-) diff --git a/block.py b/block.py index c5d9e30..c561c20 100644 --- a/block.py +++ b/block.py @@ -177,7 +177,10 @@ def CheckAndInvalidateCache(self): ## HW5 ## def VirtualToPhysical(self, virtual_block_number): - server_id = virtual_block_number // (fsconfig.TOTAL_NUM_BLOCKS) + ####### RAID 1 ####### + # server_id = virtual_block_number // (fsconfig.TOTAL_NUM_BLOCKS) + ####### RAID 4 ####### + server_id = virtual_block_number % (fsconfig.NUM_SERVERS - 1) block_number = virtual_block_number % (fsconfig.TOTAL_NUM_BLOCKS) return (server_id, block_number) @@ -187,18 +190,28 @@ def Get(self, virtual_block_number): #data, error = self.SingleGet(block_number, server_id) ####### RAID 1 ####### - for raid1_server in range(fsconfig.NUM_SERVERS): - data, error = self.SingleGet(block_number, server_id=raid1_server) + # for raid1_server in range(fsconfig.NUM_SERVERS): + # data, error = self.SingleGet(block_number, server_id=raid1_server) - if error == "SERVER_DISCONNECTED": - print("SERVER_DISCONNECTED GET " + str(virtual_block_number)) - pass + # if error == "SERVER_DISCONNECTED": + # print("SERVER_DISCONNECTED GET " + str(virtual_block_number)) + # pass - # Break if first data is not an offline server, meaning server is valid. No need to loop through all - if error != "SERVER_DISCONNECTED": - break + # # Break if first data is not an offline server, meaning server is valid. No need to loop through all + # if error != "SERVER_DISCONNECTED": + # break ##### END RAID 1 ##### + + ##### RAID 4 ##### + + data, error = self.SingleGet(block_number, server_id) + + if error == "SERVER_DISCONNECTED": + print("SERVER_DISCONNECTED GET " + str(virtual_block_number)) + pass + + ##### END RAID 4 ##### if data == -1 and error != "SERVER_DISCONNECTED": print("CORRUPTED_BLOCK " + str(virtual_block_number)) @@ -207,22 +220,51 @@ def Get(self, virtual_block_number): return data def Put(self, virtual_block_number, block_data): + print(virtual_block_number) + print(fsconfig.TOTAL_NUM_BLOCKS) server_id, block_number = self.VirtualToPhysical(virtual_block_number) - + print("server " + str(server_id)) #data, error = self.SinglePut(block_number, block_data, server_id=server_id) ####### RAID 1 ####### - for raid1_server in range(fsconfig.NUM_SERVERS): - data, error = self.SinglePut(block_number, block_data, server_id=raid1_server) + # for raid1_server in range(fsconfig.NUM_SERVERS): + # data, error = self.SinglePut(block_number, block_data, server_id=raid1_server) - if error == "SERVER_TIMEOUT" or error == "SERVER_DISCONNECTED": - print("SERVER_DISCONNECTED PUT " + str(virtual_block_number)) + # if error == "SERVER_TIMEOUT" or error == "SERVER_DISCONNECTED": + # print("SERVER_DISCONNECTED PUT " + str(virtual_block_number)) + # if data == -1 and error != "SERVER_DISCONNECTED": + # print("CORRUPTED_BLOCK " + str(virtual_block_number)) + # pass + + ####### RAID 4 ####### + + oldData, error = self.SingleGet(block_number, server_id) + currParity, error = self.SingleGet(block_number, fsconfig.NUM_SERVERS-1) + parity = bytearray(fsconfig.BLOCK_SIZE) + for i in range(fsconfig.BLOCK_SIZE): + if(oldData != -1): + parity[i] = oldData[i] ^ block_data[i] + else: + parity[i] = block_data[i] ^ 0 + for i in range(fsconfig.BLOCK_SIZE): + if(currParity != -1): + parity[i] = parity[i] ^ currParity[i] + else: + parity[i] = parity[i] ^ 0 + + data, error = self.SinglePut(block_number, block_data, server_id) + + if error == "SERVER_TIMEOUT" or error == "SERVER_DISCONNECTED": + print("SERVER_DISCONNECTED PUT " + str(virtual_block_number)) + if data == -1 and error != "SERVER_DISCONNECTED": print("CORRUPTED_BLOCK " + str(virtual_block_number)) pass + data, error = self.SinglePut(block_number, parity, fsconfig.NUM_SERVERS-1) + return 0 def RSM(self, virtual_block_number): From b84e4281d061799711e0864d64f0914a007004a0 Mon Sep 17 00:00:00 2001 From: Miguel Jara Date: Thu, 30 Nov 2023 21:56:48 -0500 Subject: [PATCH 2/4] Fix RSM and VirtualToPhyscial for RAID 4 --- block.py | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/block.py b/block.py index c561c20..528e401 100644 --- a/block.py +++ b/block.py @@ -181,7 +181,7 @@ def VirtualToPhysical(self, virtual_block_number): # server_id = virtual_block_number // (fsconfig.TOTAL_NUM_BLOCKS) ####### RAID 4 ####### server_id = virtual_block_number % (fsconfig.NUM_SERVERS - 1) - block_number = virtual_block_number % (fsconfig.TOTAL_NUM_BLOCKS) + block_number = virtual_block_number % (fsconfig.TOTAL_NUM_BLOCKS // fsconfig.NUM_SERVERS - 1) return (server_id, block_number) def Get(self, virtual_block_number): @@ -272,23 +272,24 @@ def RSM(self, virtual_block_number): # data = self.SingleRSM(block_number, server_id) ####### RAID 1 ####### - for raid1_server in range(fsconfig.NUM_SERVERS): - data, error = self.SingleRSM(block_number, server_id=raid1_server) + # for raid1_server in range(fsconfig.NUM_SERVERS): + ####### RAID 4 ####### + data, error = self.SingleRSM(block_number, server_id) - # if errors are received, pass to next server - if error == "SERVER_TIMEOUT": - print("SERVER_TIMEOUT RSM " + str(virtual_block_number)) - pass + # # if errors are received, pass to next server + # if error == "SERVER_TIMEOUT": + # print("SERVER_TIMEOUT RSM " + str(virtual_block_number)) + # pass - if error == "SERVER_DISCONNECTED": - print("SERVER_DISCONNECTED RSM " + str(virtual_block_number)) - pass + # if error == "SERVER_DISCONNECTED": + # print("SERVER_DISCONNECTED RSM " + str(virtual_block_number)) + # pass - if data == -1 and error != "SERVER_DISCONNECTED": - print("CORRUPTED_BLOCK " + str(virtual_block_number)) - pass + # if data == -1 and error != "SERVER_DISCONNECTED": + # print("CORRUPTED_BLOCK " + str(virtual_block_number)) + # pass - return data + # return data if error == "SERVER_TIMEOUT" or error == "SERVER_DISCONNECTED": # No need to print again for RAID1, handled in RAID1 loop From f1dfaed2642b8951bfe49c445ee70e56e6b9e9eb Mon Sep 17 00:00:00 2001 From: Joel Alvarez Date: Fri, 1 Dec 2023 20:31:50 -0500 Subject: [PATCH 3/4] RAID 5 functionality, and load distribution tests --- basic_tests.txt | 47 +++++++++++++- block.py | 167 ++++++++++++++++++++++++++++++++++-------------- fsconfig.py | 6 +- fsmain.py | 1 + shell.py | 2 + 5 files changed, 173 insertions(+), 50 deletions(-) diff --git a/basic_tests.txt b/basic_tests.txt index f582b89..1ed86b4 100644 --- a/basic_tests.txt +++ b/basic_tests.txt @@ -18,6 +18,51 @@ Note: Number of blocks on client side is equal to number of blocks of just one s ------ RAID 5 ------ -... +python3 fsmain.py -ns 5 -nb 1024 -bs 256 -cid 0 -port 8000 + +python3 blockserver.py -nb 256 -bs 256 -port 8000 +python3 blockserver.py -nb 256 -bs 256 -port 8001 +python3 blockserver.py -nb 256 -bs 256 -port 8002 +python3 blockserver.py -nb 256 -bs 256 -port 8003 +python3 blockserver.py -nb 256 -bs 256 -port 8004 + +--- EEL5737 data --- + +Test 0: +Number of Accesses for server 0: 4 +Number of Accesses for server 1: 69 +Number of Accesses for server 2: 93 +Number of Accesses for server 3: 63 +Number of Accesses for server 4: 54 + +Test 1: +Number of Accesses for server 0: 9 +Number of Accesses for server 1: 19 +Number of Accesses for server 2: 54 +Number of Accesses for server 3: 30 +Number of Accesses for server 4: 54 + +Test 2: +Number of Accesses for server 0: 3 +Number of Accesses for server 1: 4 +Number of Accesses for server 2: 178 +Number of Accesses for server 3: 90 +Number of Accesses for server 4: 69 + +Test 3: +Number of Accesses for server 0: 6 +Number of Accesses for server 1: 4 +Number of Accesses for server 2: 181 +Number of Accesses for server 3: 88 +Number of Accesses for server 4: 47 + +Test 4: +Number of Accesses for server 0: 0 +Number of Accesses for server 1: 7 +Number of Accesses for server 2: 63 +Number of Accesses for server 3: 74 +Number of Accesses for server 4: 35 + + -------------------- diff --git a/block.py b/block.py index 528e401..a20a5d9 100644 --- a/block.py +++ b/block.py @@ -14,6 +14,12 @@ def __init__(self): # initialize block cache empty self.blockcache = {} + # EEL 5737 + self.load_analysis = {} + + for i in range(fsconfig.NUM_SERVERS): + self.load_analysis[i] = 0 + # initialize clientID if fsconfig.CID >= 0 and fsconfig.CID < fsconfig.MAX_CLIENTS: self.clientID = fsconfig.CID @@ -41,7 +47,7 @@ def __init__(self): def SinglePut(self, block_number, block_data, server_id): logging.debug("PUT: Server id: " + str(server_id)) logging.debug("PUT: block number: " + str(block_number)) - + self.load_analysis[server_id] += 1 logging.debug( 'Put: block number ' + str(block_number) + ' len ' + str(len(block_data)) + '\n' + str(block_data.hex())) @@ -64,8 +70,8 @@ def SinglePut(self, block_number, block_data, server_id): except: return -1, "SERVER_DISCONNECTED" # update block cache - print('CACHE_WRITE_THROUGH ' + str(block_number)) - self.blockcache[block_number] = putdata + # if fsconfig.SHOW_CACHE: print('CACHE_WRITE_THROUGH ' + str(block_number)) + # self.blockcache[block_number] = putdata # flag this is the last writer # unless this is a release - which doesn't flag last writer if block_number != fsconfig.TOTAL_NUM_BLOCKS-1: @@ -95,27 +101,29 @@ def SingleGet(self, block_number, server_id): logging.debug("GET: Server id: " + str(server_id)) logging.debug("GET: block number: " + str(block_number)) + self.load_analysis[server_id] += 1 + logging.debug('Get: ' + str(block_number)) if block_number in range(0, fsconfig.TOTAL_NUM_BLOCKS): - # logging.debug ('\n' + str((self.block[block_number]).hex())) - # commenting this out as the request now goes to the server - # return self.block[block_number] - # call Get() method on the server - # don't look up cache for last two blocks - if (block_number < fsconfig.TOTAL_NUM_BLOCKS-2) and (block_number in self.blockcache): - print('CACHE_HIT '+ str(block_number)) - data = self.blockcache[block_number] - else: - print('CACHE_MISS ' + str(block_number)) - try: - data = self.block_servers[server_id].Get(block_number) - except socket.timeout: - print("SERVER_TIMED_OUT") - return -1, "SERVER_TIMEOUT" - except: - return -1, "SERVER_DISCONNECTED" - # add to cache - self.blockcache[block_number] = data + # # logging.debug ('\n' + str((self.block[block_number]).hex())) + # # commenting this out as the request now goes to the server + # # return self.block[block_number] + # # call Get() method on the server + # # don't look up cache for last two blocks + # if (block_number < fsconfig.TOTAL_NUM_BLOCKS-2) and (block_number in self.blockcache): + # if fsconfig.SHOW_CACHE: print('CACHE_HIT '+ str(block_number)) + # data = self.blockcache[block_number] + # else: + # if fsconfig.SHOW_CACHE: print('CACHE_MISS ' + str(block_number)) + try: + data = self.block_servers[server_id].Get(block_number) + except socket.timeout: + print("SERVER_TIMED_OUT") + return -1, "SERVER_TIMEOUT" + except: + return -1, "SERVER_DISCONNECTED" + # add to cache + # self.blockcache[block_number] = data # return as bytearray return bytearray(data), None @@ -126,6 +134,9 @@ def SingleGet(self, block_number, server_id): def SingleRSM(self, block_number, server_id): logging.debug('RSM: ' + str(block_number)) + + self.load_analysis[server_id] += 1 + if block_number in range(0, fsconfig.TOTAL_NUM_BLOCKS): try: data = self.block_servers[server_id].RSM(block_number) @@ -168,7 +179,7 @@ def CheckAndInvalidateCache(self): last_writer = self.Get(LAST_WRITER_BLOCK) # if ID of last writer is not self, invalidate and update if last_writer[0] != fsconfig.CID: - print("CACHE_INVALIDATED") + if fsconfig.SHOW_CACHE: print("CACHE_INVALIDATED") self.blockcache = {} updated_block = bytearray(fsconfig.BLOCK_SIZE) updated_block[0] = fsconfig.CID @@ -181,12 +192,45 @@ def VirtualToPhysical(self, virtual_block_number): # server_id = virtual_block_number // (fsconfig.TOTAL_NUM_BLOCKS) ####### RAID 4 ####### server_id = virtual_block_number % (fsconfig.NUM_SERVERS - 1) - block_number = virtual_block_number % (fsconfig.TOTAL_NUM_BLOCKS // fsconfig.NUM_SERVERS - 1) - return (server_id, block_number) + # physical_block_num = virtual_block_number % (fsconfig.TOTAL_NUM_BLOCKS // (fsconfig.NUM_SERVERS - 1)) # WORKS + ####### RAID 5 ####### + # Code for determining parity server and block number + level = (virtual_block_number // (fsconfig.NUM_SERVERS - 1)) % fsconfig.NUM_SERVERS + parity_server_id = fsconfig.NUM_SERVERS - level - 1 + + # Block number is same for parity and data in raid 5 + physical_block_num = (virtual_block_number // (fsconfig.NUM_SERVERS - 1)) + + # Code for determining data server + if level == 0: + raid5_data_server_id = server_id + if level == 1: + if server_id >= 3: + raid5_data_server_id = server_id + 1 + else: + raid5_data_server_id = server_id + if level == 2: + if server_id >= 2: + raid5_data_server_id = server_id + 1 + else: + raid5_data_server_id = server_id + if level == 3: + if server_id >= 1: + raid5_data_server_id = server_id + 1 + else: + raid5_data_server_id = server_id + if level == 4: + raid5_data_server_id = server_id + 1 - def Get(self, virtual_block_number): - server_id, block_number = self.VirtualToPhysical(virtual_block_number) + # print("virtual: " + str(virtual_block_number)) + # print("physical: " + str(physical_block_num)) + # print("level: " + str(level)) + # print("data server id: " + str(raid5_data_server_id)) + # print("parity server id: " + str(parity_server_id)) + + return (physical_block_num, raid5_data_server_id, parity_server_id) + def Get(self, virtual_block_number): #data, error = self.SingleGet(block_number, server_id) ####### RAID 1 ####### @@ -204,12 +248,36 @@ def Get(self, virtual_block_number): ##### END RAID 1 ##### ##### RAID 4 ##### - - data, error = self.SingleGet(block_number, server_id) - if error == "SERVER_DISCONNECTED": - print("SERVER_DISCONNECTED GET " + str(virtual_block_number)) - pass + ##### RAID 5 ##### + + if virtual_block_number in range(0, fsconfig.TOTAL_NUM_BLOCKS): + # logging.debug ('\n' + str((self.block[block_number]).hex())) + # commenting this out as the request now goes to the server + # return self.block[block_number] + # call Get() method on the server + # don't look up cache for last two blocks + if (virtual_block_number < fsconfig.TOTAL_NUM_BLOCKS-2) and (virtual_block_number in self.blockcache): + if fsconfig.SHOW_CACHE: print('CACHE_HIT '+ str(virtual_block_number)) + data = self.blockcache[virtual_block_number] + else: + if fsconfig.SHOW_CACHE: print('CACHE_MISS ' + str(virtual_block_number)) + try: + block_number, server_id, _ = self.VirtualToPhysical(virtual_block_number) + data, error = self.SingleGet(block_number, server_id) + if error == "SERVER_DISCONNECTED": + print("SERVER_DISCONNECTED GET " + str(virtual_block_number)) + except socket.timeout: + print("SERVER_TIMED_OUT") + return -1, "SERVER_TIMEOUT" + except: + return -1, "SERVER_DISCONNECTED" + # add to cache + self.blockcache[virtual_block_number] = data + # return as bytearray + # return bytearray(data), None + + pass ##### END RAID 4 ##### @@ -220,10 +288,10 @@ def Get(self, virtual_block_number): return data def Put(self, virtual_block_number, block_data): - print(virtual_block_number) - print(fsconfig.TOTAL_NUM_BLOCKS) - server_id, block_number = self.VirtualToPhysical(virtual_block_number) - print("server " + str(server_id)) + # print(virtual_block_number) + # print(fsconfig.TOTAL_NUM_BLOCKS) + block_number, raid5_data_server_id, parity_server_id = self.VirtualToPhysical(virtual_block_number) + # print("server " + str(server_id)) #data, error = self.SinglePut(block_number, block_data, server_id=server_id) ####### RAID 1 ####### @@ -239,9 +307,11 @@ def Put(self, virtual_block_number, block_data): # pass ####### RAID 4 ####### - - oldData, error = self.SingleGet(block_number, server_id) - currParity, error = self.SingleGet(block_number, fsconfig.NUM_SERVERS-1) + + ####### RAID 5 ####### + + oldData, error = self.SingleGet(block_number, raid5_data_server_id) + currParity, error = self.SingleGet(block_number, parity_server_id) parity = bytearray(fsconfig.BLOCK_SIZE) for i in range(fsconfig.BLOCK_SIZE): if(oldData != -1): @@ -254,7 +324,10 @@ def Put(self, virtual_block_number, block_data): else: parity[i] = parity[i] ^ 0 - data, error = self.SinglePut(block_number, block_data, server_id) + if fsconfig.SHOW_CACHE: print('CACHE_WRITE_THROUGH ' + str(block_number)) + self.blockcache[virtual_block_number] = block_data + + data, error = self.SinglePut(block_number, block_data, raid5_data_server_id) if error == "SERVER_TIMEOUT" or error == "SERVER_DISCONNECTED": print("SERVER_DISCONNECTED PUT " + str(virtual_block_number)) @@ -263,12 +336,12 @@ def Put(self, virtual_block_number, block_data): print("CORRUPTED_BLOCK " + str(virtual_block_number)) pass - data, error = self.SinglePut(block_number, parity, fsconfig.NUM_SERVERS-1) + data, error = self.SinglePut(block_number, parity, parity_server_id) return 0 def RSM(self, virtual_block_number): - server_id, block_number = self.VirtualToPhysical(virtual_block_number) + block_number, server_id, _ = self.VirtualToPhysical(virtual_block_number) # data = self.SingleRSM(block_number, server_id) ####### RAID 1 ####### @@ -277,13 +350,11 @@ def RSM(self, virtual_block_number): data, error = self.SingleRSM(block_number, server_id) # # if errors are received, pass to next server - # if error == "SERVER_TIMEOUT": - # print("SERVER_TIMEOUT RSM " + str(virtual_block_number)) - # pass + if error == "SERVER_TIMEOUT": + print("SERVER_TIMEOUT RSM " + str(virtual_block_number)) - # if error == "SERVER_DISCONNECTED": - # print("SERVER_DISCONNECTED RSM " + str(virtual_block_number)) - # pass + if error == "SERVER_DISCONNECTED": + print("SERVER_DISCONNECTED RSM " + str(virtual_block_number)) # if data == -1 and error != "SERVER_DISCONNECTED": # print("CORRUPTED_BLOCK " + str(virtual_block_number)) diff --git a/fsconfig.py b/fsconfig.py index ab11b11..85ccb4a 100644 --- a/fsconfig.py +++ b/fsconfig.py @@ -14,7 +14,7 @@ def ConfigureFSConstants(args): # Basic and derived file system configuration parameters are stored in global variables # Call this function with args (from command-line arguments) to configure the file system - global TOTAL_NUM_BLOCKS, BLOCK_SIZE, MAX_NUM_INODES, INODE_SIZE, NUM_SERVERS + global TOTAL_NUM_BLOCKS, BLOCK_SIZE, MAX_NUM_INODES, INODE_SIZE, NUM_SERVERS, SHOW_CACHE global CID, PORT, MAX_CLIENTS, SERVER_ADDRESS, RSM_UNLOCKED, RSM_LOCKED, SOCKET_TIMEOUT, RETRY_INTERVAL # Default values # Total number of blocks in raw storage @@ -43,6 +43,10 @@ def ConfigureFSConstants(args): PORT = args.port if args.num_servers: NUM_SERVERS = args.num_servers + if args.show_cache: + SHOW_CACHE = args.show_cache + else: + SHOW_CACHE = 0 # These are constants that SHOULD NEVER BE MODIFIED global MAX_FILENAME, INODE_NUMBER_DIRENTRY_SIZE, FREEBITMAP_BLOCK_OFFSET, INODE_BYTES_SIZE_TYPE_REFCNT, \ diff --git a/fsmain.py b/fsmain.py index e8e1fcf..bc59bc5 100644 --- a/fsmain.py +++ b/fsmain.py @@ -30,6 +30,7 @@ ap.add_argument('-cid', '--client_id', type=int, help='an integer value') ap.add_argument('-port', '--port', type=int, help='an integer value') ap.add_argument('-ns', '--num_servers', type=int, help='an integer value') + ap.add_argument('-sc', '--show_cache', type=int, help='an integer value') # Other than FS args, consecutive args will be captured in by 'arg' as list ap.add_argument('arg', nargs='*') diff --git a/shell.py b/shell.py index e633c34..1e58021 100644 --- a/shell.py +++ b/shell.py @@ -381,6 +381,8 @@ def Interpreter(self): self.lns(splitcmd[1], splitcmd[2]) self.RawBlocks.Release() elif splitcmd[0] == "exit": + for i in range(fsconfig.NUM_SERVERS): + print(f"Number of Accesses for server {i}: {self.RawBlocks.load_analysis[i]}", ) return else: print ("command " + splitcmd[0] + " not valid.\n") From 67657ab6930f56a6d21a76a2569e14c84975034c Mon Sep 17 00:00:00 2001 From: Joel Alvarez Date: Fri, 7 Feb 2025 10:57:01 -0500 Subject: [PATCH 4/4] Create README.md --- README.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..08981e4 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +RAID 5 filesystem implemented for Principles of Computer System Design