-
Notifications
You must be signed in to change notification settings - Fork 0
06_system_configuration.md
Welcome back, cdfs-ton adventurer! In our last chapter, Fault Tolerance & Replication Monitoring, we learned how cdfs-ton bravely keeps your data safe even when things go wrong, constantly watching and making new copies.
Now, imagine you've built a fantastic distributed file system like cdfs-ton. It has a Metadata Server, many Storage Nodes, and Client Applications that all need to talk to each other. But how do they know where to find each other? How does a Storage Node know which folder on its own computer it should use to store your data chunks?
You wouldn't want to dig into the C code and change numbers every time you move the Metadata Server to a different computer, or decide to store chunks in a new directory, right? That would be like having to rebuild your car's engine just to change the radio station!
This is where System Configuration comes in. It's like the master "settings panel" or "instruction manual" for your entire cdfs-ton system. Instead of hardcoding important details directly into the program code, we put them into a simple, easy-to-read file. This allows you to easily adjust network locations, storage paths, and other parameters without needing to recompile any code. It makes your cdfs-ton system flexible and easy to deploy in different environments.
If the IP address of the Metadata Server was permanently written into the cdfs_client program, what would happen if the Metadata Server's computer got a new IP address? Every single cdfs_client program would stop working until it was recompiled with the new address! This is not very "distributed" or "friendly."
cdfs-ton solves this by using a plain text file, typically named cdfs.conf. This file contains all the important "settings" that various parts of cdfs-ton need to know. When a client, a Metadata Server, or a Storage Node starts up, its first job is to read this cdfs.conf file to get its instructions.
Let's look at an example cdfs.conf file:
# File: cdfs.conf
META_IP=127.0.0.1
META_PORT=8080
STORAGE_DIR=./storage_data
This file tells us:
-
META_IP=127.0.0.1: The Metadata Server can be found at the IP address127.0.0.1. (This is a special IP meaning "this computer itself," useful for testing.) -
META_PORT=8080: The Metadata Server listens for connections on port8080. -
STORAGE_DIR=./storage_data: Any Storage Node reading this config should store its chunks in a folder namedstorage_datain the same directory where it's run.
You can change these values in the cdfs.conf file, save it, and restart your cdfs-ton components, and they will pick up the new settings immediately! No recompiling required.
All the important settings for cdfs-ton are stored in a simple structure in memory after reading the cdfs.conf file. This structure is called cdfs_config_t.
// File: common/config.h
#define MAX_IP_LEN 16
typedef struct {
uint8_t meta_ip[MAX_IP_LEN]; // IP address of the Metadata Server
int32_t meta_port; // Port of the Metadata Server
uint8_t storage_dir[256]; // Directory for Storage Node data
} cdfs_config_t;Let's break down these important settings:
| Parameter Name | Description | Used by |
|---|---|---|
meta_ip |
The IP address where the Metadata Server is running. | Client Applications, Storage Nodes, Metadata Server (for self-addressing) |
meta_port |
The network port the Metadata Server listens on. | Client Applications, Storage Nodes, Metadata Server (for self-addressing) |
storage_dir |
The local directory where a Storage Node stores its data chunks. | Storage Nodes (to initialize their storage) |
These parameters are crucial because they allow all components of cdfs-ton to correctly locate and communicate with each other.
When any part of cdfs-ton starts, it calls a special function, load_config, to read the cdfs.conf file and fill in the cdfs_config_t structure.
sequenceDiagram
participant Component as CDFS Component (Client/MD/SN)
participant ConfigFile as cdfs.conf file
participant ConfigStruct as cdfs_config_t in memory
Component->>Component: 1. Start up
Component->>Component: 2. Call load_config("cdfs.conf", &my_config)
Component->>ConfigFile: 3. Open cdfs.conf for reading
ConfigFile-->>Component: 4. Read each line (e.g., "META_IP=127.0.0.1")
Component->>ConfigStruct: 5. Parse line and store value in my_config.meta_ip
Component->>ConfigStruct: 6. Parse next line and store value in my_config.meta_port
Component->>ConfigStruct: 7. Parse next line and store value in my_config.storage_dir
Component->>ConfigFile: 8. Close cdfs.conf
Component->>Component: 9. Now use settings from my_config (e.g., connect to my_config.meta_ip)
The load_config function, found in common/config.c, is responsible for reading the cdfs.conf file.
// File: common/config.c (simplified)
#include "config.h" // Includes the cdfs_config_t definition
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int32_t load_config(const uint8_t *filename, cdfs_config_t *out_config) {
// Set some default values first, in case the config file is missing
strncpy((char *)out_config->meta_ip, "127.0.0.1", MAX_IP_LEN - 1);
out_config->meta_port = 8080;
strncpy((char *)out_config->storage_dir, "./storage_data", sizeof(out_config->storage_dir) - 1);
FILE *fp = fopen((const char *)filename, "r"); // Try to open the config file
if (!fp) {
printf("Could not open config file %s, using defaults.\n", (const char *)filename);
return 0; // Succeed with defaults if file not found
}
uint8_t line[256];
while (fgets((char *)line, sizeof(line), fp)) { // Read line by line
uint8_t *key = (uint8_t *)strtok((char *)line, "="); // Split by '='
uint8_t *val = (uint8_t *)strtok(NULL, "\n"); // Get value part
if (key && val) {
if (strcmp((char *)key, "META_IP") == 0) {
strncpy((char *)out_config->meta_ip, (char *)val, MAX_IP_LEN - 1);
} else if (strcmp((char *)key, "META_PORT") == 0) {
out_config->meta_port = atoi((char *)val); // Convert string to integer
} else if (strcmp((char *)key, "STORAGE_DIR") == 0) {
strncpy((char *)out_config->storage_dir, (char *)val, sizeof(out_config->storage_dir) - 1);
}
}
}
fclose(fp); // Close the file
return 0; // Configuration loaded successfully
}Let's walk through this code:
-
Default Values: At the start, the function sets some common default values (e.g.,
127.0.0.1for IP,8080for port). This is a good practice because if thecdfs.conffile is missing or a particular setting isn't found,cdfs-toncan still run with sensible defaults instead of crashing. -
Open File:
fopentries to open thecdfs.conffile for reading. If it fails (e.g., the file doesn't exist), it prints a message and uses the default values. -
Read Line by Line: The
while (fgets(...))loop reads thecdfs.conffile one line at a time. -
Parse Key-Value Pairs:
-
strtok((char *)line, "=")breaks each line into two parts using the=symbol. The first part is thekey(like "META_IP"), and the second part (obtained withstrtok(NULL, "\n")) is theval(like "127.0.0.1"). -
strcmp((char *)key, "META_IP") == 0)checks if thekeymatches "META_IP". If it does,strncpycopies theval(the IP address string) into theout_config->meta_ipfield.strncpyis used to prevent buffer overflows, ensuring we don't copy more characters than the array can hold. - If the key is "META_PORT",
atoi((char *)val)converts the text value (like "8080") into an actual number and stores it inout_config->meta_port. - The
STORAGE_DIRis handled similarly.
-
-
Close File: After reading all lines,
fclose(fp)closes the configuration file.
This simple mechanism allows cdfs-ton to dynamically load its settings.
Once load_config has filled the cdfs_config_t structure, any component (client, Metadata Server, Storage Node) can access these settings using the config variable.
For example, from Chapter 1: Client Application Interface, remember how the client connected to the Metadata Server? It used config.meta_ip and config.meta_port:
// File: client/dfs_client.c (simplified connection to Metadata Server)
static int32_t connect_to_server(const uint8_t *ip, int32_t port) {
int32_t sock = 0;
// ... setup network socket ...
if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
// ... error handling ...
return -1;
}
return sock; // Returns a socket connection
}
int32_t cdfs_put(const uint8_t *local_path, const uint8_t *cdfs_path) {
// ...
// Connect using the values read from cdfs.conf
int32_t meta_sock = connect_to_server((const uint8_t *)config.meta_ip, config.meta_port);
// ...
return 0;
}Here, config is a global variable of type cdfs_config_t that was populated by load_config at the start of the client program.
Similarly, in Chapter 3: Chunk Storage & Management, the Storage Node's heartbeat_thread uses the configured Metadata Server IP and port:
// File: storage_node/storage_node.c (simplified heartbeat_thread)
// g_config is a global cdfs_config_t variable
void* heartbeat_thread(void* arg) {
// ...
int32_t sock = connect_to(g_config.meta_ip, g_config.meta_port);
// ...
return NULL;
}And the Storage Node itself knows where to store its data using g_config.storage_dir:
// File: storage_node/storage.c (simplified storage_init)
static uint8_t g_storage_dir[256] = "./storage_data"; // Default fallback
void storage_init(const uint8_t *dir) {
// The 'dir' parameter usually comes from g_config.storage_dir
strncpy((char *)g_storage_dir, (const char *)dir, sizeof(g_storage_dir) - 1);
mkdir((const char *)g_storage_dir, 0755);
}This ensures that all parts of cdfs-ton consistently use the same, easily adjustable settings.
System Configuration is the unsung hero that brings flexibility and ease of management to cdfs-ton. By centralizing important settings in a simple cdfs.conf file, you can effortlessly change network addresses, storage locations, and other parameters without ever touching the program's source code. This makes cdfs-ton easier to set up, adapt, and operate in various network environments, truly embodying the spirit of a distributed system.
Next, we'll delve into how the Metadata Server makes sure all that precious metadata about your files isn't lost if the server itself crashes, by exploring Persisted Metadata (FSImage & Edit Log).