Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
RAID 5 filesystem implemented for Principles of Computer System Design
47 changes: 46 additions & 1 deletion basic_tests.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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



--------------------
226 changes: 170 additions & 56 deletions block.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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()))
Expand All @@ -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:
Expand Down Expand Up @@ -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

Expand All @@ -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)
Expand Down Expand Up @@ -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
Expand All @@ -177,28 +188,98 @@ def CheckAndInvalidateCache(self):
## HW5 ##

def VirtualToPhysical(self, virtual_block_number):
server_id = virtual_block_number // (fsconfig.TOTAL_NUM_BLOCKS)
block_number = virtual_block_number % (fsconfig.TOTAL_NUM_BLOCKS)
return (server_id, block_number)
####### RAID 1 #######
# server_id = virtual_block_number // (fsconfig.TOTAL_NUM_BLOCKS)
####### RAID 4 #######
server_id = virtual_block_number % (fsconfig.NUM_SERVERS - 1)
# 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 #######
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 #####

##### 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 #####

if data == -1 and error != "SERVER_DISCONNECTED":
print("CORRUPTED_BLOCK " + str(virtual_block_number))
Expand All @@ -207,46 +288,79 @@ def Get(self, virtual_block_number):
return data

def Put(self, virtual_block_number, block_data):
server_id, block_number = self.VirtualToPhysical(virtual_block_number)

# 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 #######
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 #######

####### 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):
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

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))

if data == -1 and error != "SERVER_DISCONNECTED":
print("CORRUPTED_BLOCK " + str(virtual_block_number))
pass

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 #######
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))

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))
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
Expand Down
6 changes: 5 additions & 1 deletion fsconfig.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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, \
Expand Down
1 change: 1 addition & 0 deletions fsmain.py
Original file line number Diff line number Diff line change
Expand Up @@ -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='*')
Expand Down
Loading