from abc import ABC, abstractmethod
from ssd.common import LBA_LOWER_LIMIT, LBA_UPPER_LIMIT, is_valid_hex
from ssd.common import ERASE_SIZE_LOWER_LIMIT, ERASE_SIZE_UPPER_LIMIT
from typing import List, Tuple
[docs]
class Command(ABC):
"""
기본 명령어 클래스입니다.
Attributes:
option (str): 명령 옵션
args (list): 명령 인자 리스트
"""
def __init__(self, args: List[str]):
"""
Command 클래스의 생성자. 명령 옵션과 인자를 설정합니다.
Args:
args (list): 명령 인자 리스트
"""
self.validate_command()
@abstractmethod
[docs]
def validate_command(self):
pass
[docs]
def get_value(self) -> List[str]:
"""
명령 인자를 반환합니다.
Returns:
list: 명령 인자 리스트
"""
return self.args
[docs]
def get_key(self):
pass
[docs]
class ReadCommand(Command):
"""
읽기 명령어 클래스입니다.
Attributes:
lba (int): 논리 블록 주소
"""
def __init__(self, args: List[str]):
"""
ReadCommand 클래스의 생성자. 논리 블록 주소를 설정합니다.
Args:
args (list): 명령 인자 리스트
"""
super().__init__(args)
[docs]
self.lba = int(args[1])
[docs]
def validate_command(self):
if len(self.args) != 2:
raise ValueError("명령을 수행하기 위한 인자가 부족합니다. ex) ssd R 20")
def is_integer(s: str) -> bool:
try:
int(s)
return True
except ValueError:
return False
if not is_integer(self.args[1]):
raise ValueError('LBA는 정수여야합니다.')
if not LBA_LOWER_LIMIT <= int(self.args[1]) <= LBA_UPPER_LIMIT:
raise ValueError(f'LBA는 {LBA_LOWER_LIMIT} ~ {LBA_UPPER_LIMIT} 여야합니다.')
return True
[docs]
def get_key(self) -> Tuple[str, int]:
"""
명령 키를 반환합니다.
Returns:
tuple: 명령 키 (옵션, LBA)
"""
return self.option, self.lba
[docs]
class WriteCommand(Command):
"""
쓰기 명령어 클래스입니다.
Attributes:
lba (int): 논리 블록 주소
value (int): 쓸 값 (16진수 형식)
"""
def __init__(self, args: List[str]):
"""
WriteCommand 클래스의 생성자. 논리 블록 주소와 쓸 값을 설정합니다.
Args:
args (list): 명령 인자 리스트
"""
super().__init__(args)
[docs]
self.lba = int(args[1])
[docs]
self.value = int(args[2], 16)
[docs]
def validate_command(self):
if len(self.args) != 3:
raise ValueError("명령을 수행하기 위한 인자가 부족합니다. ex) ssd W 20 0x1234ABCD")
if not self.args[1].isdigit():
raise ValueError('LBA는 숫자여야합니다.')
if not LBA_LOWER_LIMIT <= int(self.args[1]) <= LBA_UPPER_LIMIT:
raise ValueError(f'LBA는 {LBA_LOWER_LIMIT} ~ {LBA_UPPER_LIMIT} 여야합니다.')
if not is_valid_hex(self.args[2]):
raise ValueError('value는 0x00000000 형식이여야 합니다.')
return True
[docs]
def get_key(self) -> Tuple[str, int, int]:
"""
명령 키를 반환합니다.
Returns:
tuple: 명령 키 (옵션, 시작 LBA, 끝 LBA)
"""
return self.option, self.lba, self.lba + 1
[docs]
class EraseCommand(Command):
"""
삭제 명령어 클래스입니다.
Attributes:
lba (int): 논리 블록 주소
size (int): 삭제할 블록 수
"""
def __init__(self, args: List[str]):
"""
EraseCommand 클래스의 생성자. 논리 블록 주소와 삭제할 블록 수를 설정합니다.
Args:
args (list): 명령 인자 리스트
"""
super().__init__(args)
[docs]
self.lba = int(args[1])
[docs]
self.size = int(args[2])
[docs]
def validate_command(self):
if len(self.args) != 3:
raise ValueError("명령을 수행하기 위한 인자가 부족합니다. ex) ssd E 20 4")
if not self.args[1].isdigit():
raise ValueError('LBA는 숫자여야합니다.')
if not self.args[2].isdigit():
raise ValueError('SIZE는 숫자여야합니다.')
if not LBA_LOWER_LIMIT <= int(self.args[1]) <= LBA_UPPER_LIMIT:
raise ValueError(f'LBA는 {LBA_LOWER_LIMIT} ~ {LBA_UPPER_LIMIT} 여야합니다.')
if not ERASE_SIZE_LOWER_LIMIT <= int(self.args[2]) <= ERASE_SIZE_UPPER_LIMIT:
raise ValueError(f"SIZE는 {ERASE_SIZE_LOWER_LIMIT} ~ {ERASE_SIZE_UPPER_LIMIT} 여야합니다.")
return True
[docs]
def get_key(self) -> Tuple[str, int, int]:
"""
명령 키를 반환합니다.
Returns:
tuple: 명령 키 (옵션, 시작 LBA, 끝 LBA)
"""
return self.option, self.lba, self.lba + self.size
[docs]
class FlushCommand(Command):
"""
명령어 Buffer를 비우는 명령어 클래스입니다.
Attributes:
-
"""
def __init__(self, args):
"""
FlushCommand 클래스의 생성자. 논리 블록 주소와 삭제할 블록 수를 설정합니다.
Args:
args (list): 명령 인자 리스트
"""
super().__init__(args)
[docs]
def validate_command(self):
if len(self.args) != 1:
raise ValueError("명령을 수행하기 위한 인자가 부족합니다. ex) ssd F")
return True
[docs]
class CommandFactory:
"""
명령어 생성 클래스입니다.
주어진 명령 인자 리스트를 통해 적절한 명령어 객체를 생성합니다.
"""
@staticmethod
[docs]
def parse_command(arg_list: List[str]) -> Command:
"""
주어진 명령 인자 리스트를 통해 적절한 명령어 객체를 생성합니다.
Args:
arg_list (list): 명령 인자 리스트
Returns:
Command: 생성된 명령어 객체
"""
name = arg_list[0]
if name == 'R':
return ReadCommand(arg_list)
elif name == 'W':
return WriteCommand(arg_list)
elif name == 'E':
return EraseCommand(arg_list)
elif name == 'F':
return FlushCommand(arg_list)
else:
raise ValueError('R, W, E, F 중 하나를 사용해주세요.(대문자)')