Utils
The Utils module provides essential utility functions for network communication, data hashing, and system operations in the GFS implementation.
Core Functions
Data Hashing
def get_chunk_hash(data: bytes) -> str: """Generate a unique hash for chunk data.""" hash_value = hashlib.sha256(data).hexdigest() return hash_valueFeatures:
- SHA-256 hashing algorithm
- Unique chunk identification
- Data integrity verification
- Binary data handling
Network Utilities
- Port Management
def find_free_port() -> int: """Find a free port to use for a new chunk server.""" with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.bind(('', 0)) s.listen(1) port = s.getsockname()[1] return portFeatures:
- Automatic port discovery
- System port availability check
- Dynamic server allocation
Message Protocol
- Message Sending
def send_message(sock: socket.socket, message: Any): """Send a pickled message over a socket with length prefix.""" data = pickle.dumps(message) length = struct.pack('!I', len(data)) sock.sendall(length + data)Key aspects:
- Length-prefixed messages
- Pickle serialization
- Network byte order
- Atomic sending
- Message Receiving
def receive_message(sock: socket.socket) -> Any: """Receive a pickled message from a socket with length prefix.""" # Read message length length_data = sock.recv(4) length = struct.unpack('!I', length_data)[0]
# Read message in chunks chunks = [] bytes_received = 0 while bytes_received < length: chunk = sock.recv(min(length - bytes_received, 4096)) chunks.append(chunk) bytes_received += len(chunk)
return pickle.loads(b''.join(chunks))Features:
- Chunked reading
- Buffer management
- Connection monitoring
- Error handling
Implementation Details
Message Format
+---------------+------------------+| Length (4B) | Pickled Data |+---------------+------------------+-
Length Prefix
- 4 bytes (unsigned integer)
- Network byte order (big-endian)
- Maximum message size: 4GB
-
Data Section
- Pickle-serialized data
- Variable length
- Supports complex Python objects
Error Handling
- Connection Errors
try: peer = sock.getpeername() # ... message handling ...except Exception as e: logger.error(f"Error receiving message: {e}", exc_info=True) return None- Incomplete Messages
if not chunk: logger.warning("Connection closed before receiving complete message") return NoneLogging Integration
logger = GFSLogger.get_logger('utils')
# Debug logginglogger.debug(f"Generating hash for chunk of size {len(data)} bytes")logger.debug(f"Found free port: {port}")logger.debug(f"Sending message to {sock.getpeername()}")Features:
- Component-specific logging
- Debug information
- Error tracking
- Operation monitoring
Best Practices
-
Socket Management
- Use context managers
- Handle connection timeouts
- Clean up resources
- Monitor connection state
-
Data Handling
- Verify message integrity
- Handle partial reads
- Implement timeouts
- Buffer size management
-
Error Recovery
- Connection retries
- Graceful degradation
- Resource cleanup
- Error logging
Usage Examples
- Message Communication
# Sending a messagesock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)sock.connect(('localhost', 5000))send_message(sock, {'command': 'hello', 'data': 'world'})
# Receiving a messageresponse = receive_message(sock)print(response)- Port Management
# Find and use a free portport = find_free_port()server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)server_socket.bind(('localhost', port))- Data Hashing
# Generate chunk hashdata = b"chunk data"hash_value = get_chunk_hash(data)print(f"Chunk hash: {hash_value}")Performance Considerations
-
Message Chunking
- Optimal chunk size (4KB)
- Memory efficiency
- Network performance
- Buffer management
-
Serialization
- Pickle protocol version
- Data structure optimization
- Memory usage
- Security considerations