Skip to content

06_system_configuration.md

Lavnish edited this page Mar 31, 2026 · 1 revision

Chapter 6: System Configuration

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.

The Problem: Hardcoded Values are Inflexible

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."

The Solution: A Configuration File!

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.

Your System's Instruction Manual: cdfs.conf

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 address 127.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 port 8080.
  • STORAGE_DIR=./storage_data: Any Storage Node reading this config should store its chunks in a folder named storage_data in 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.

Key Concepts: Configuration Parameters

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.

How cdfs-ton Reads the Configuration

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

Diving Deeper: Inside the load_config Code

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:

  1. Default Values: At the start, the function sets some common default values (e.g., 127.0.0.1 for IP, 8080 for port). This is a good practice because if the cdfs.conf file is missing or a particular setting isn't found, cdfs-ton can still run with sensible defaults instead of crashing.
  2. Open File: fopen tries to open the cdfs.conf file for reading. If it fails (e.g., the file doesn't exist), it prints a message and uses the default values.
  3. Read Line by Line: The while (fgets(...)) loop reads the cdfs.conf file one line at a time.
  4. Parse Key-Value Pairs:
    • strtok((char *)line, "=") breaks each line into two parts using the = symbol. The first part is the key (like "META_IP"), and the second part (obtained with strtok(NULL, "\n")) is the val (like "127.0.0.1").
    • strcmp((char *)key, "META_IP") == 0) checks if the key matches "META_IP". If it does, strncpy copies the val (the IP address string) into the out_config->meta_ip field. strncpy is 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 in out_config->meta_port.
    • The STORAGE_DIR is handled similarly.
  5. Close File: After reading all lines, fclose(fp) closes the configuration file.

This simple mechanism allows cdfs-ton to dynamically load its settings.

How Components Use the Loaded Configuration

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.

Conclusion

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