69天探索操作系统-第27天:文件分配方法

170 阅读14分钟

Pro2.avif

1.介绍

文件分配方法决定了文件是如何在磁盘存储设备上物理存储的。这些方法对于高效利用存储空间和快速访问文件至关重要,直接影响系统性能和存储效率。

分配方法的选用影响碎片化、文件访问速度和存储利用率。 每个方法都有其自身的优缺点,使其适用于不同的用例和存储要求。

image.png

2.连续分配

连续分配要求文件存储在磁盘上的连续块中。这种方法类似于早期计算机系统中的内存分配,其中每个文件占据连续的块序列。

连续分配的主要优势是其出色的读取性能,因为整个文件可以在一次磁盘操作中读取完毕。然而,它也面临着外部碎片的问题,使得扩展文件变得困难,因为可能没有足够的连续空间可用。

typedef struct ContiguousFile {
    int start_block;      // Starting block number
    int length;          // Number of blocks
    char name[256];
    size_t size;
} ContiguousFile;

typedef struct ContiguousAllocator {
    int *disk_blocks;    // Array representing disk blocks
    int total_blocks;
    int free_blocks;
} ContiguousAllocator;

ContiguousAllocator* init_contiguous_allocator(int total_blocks) {
    ContiguousAllocator *allocator = malloc(sizeof(ContiguousAllocator));
    if (!allocator) return NULL;

    allocator->disk_blocks = calloc(total_blocks, sizeof(int));
    if (!allocator->disk_blocks) {
        free(allocator);
        return NULL;
    }

    allocator->total_blocks = total_blocks;
    allocator->free_blocks = total_blocks;
    return allocator;
}

// Allocate contiguous blocks
int allocate_contiguous(ContiguousAllocator *allocator, int blocks_needed) {
    int current_count = 0;
    int start_block = -1;

    for (int i = 0; i < allocator->total_blocks; i++) {
        if (allocator->disk_blocks[i] == 0) {
            if (current_count == 0) start_block = i;
            current_count++;
            
            if (current_count == blocks_needed) {
                // Mark blocks as allocated
                for (int j = start_block; j < start_block + blocks_needed; j++) {
                    allocator->disk_blocks[j] = 1;
                }
                allocator->free_blocks -= blocks_needed;
                return start_block;
            }
        } else {
            current_count = 0;
        }
    }
    return -1; // Not enough contiguous space
}

3.链式分配

链式分配存储文件为块的链接列表。每一个块都包含数据和一个指向下一个块的指针,这允许文件跨磁盘存储在非连续的块中。

这种方法消除了外部碎片,并允许文件轻松增长,但由于单个被损坏的指针可以破坏链条,因此它的随机访问性能较差,稳定性存在问题。

typedef struct LinkedBlock {
    int block_number;
    int next_block;
    char data[BLOCK_SIZE];
} LinkedBlock;

typedef struct LinkedFile {
    int first_block;
    int last_block;
    char name[256];
    size_t size;
} LinkedFile;

typedef struct LinkedAllocator {
    LinkedBlock *disk_blocks;
    int total_blocks;
    int free_blocks;
    int *free_list;  // Stack of free blocks
} LinkedAllocator;

LinkedAllocator* init_linked_allocator(int total_blocks) {
    LinkedAllocator *allocator = malloc(sizeof(LinkedAllocator));
    if (!allocator) return NULL;

    allocator->disk_blocks = calloc(total_blocks, sizeof(LinkedBlock));
    allocator->free_list = malloc(total_blocks * sizeof(int));
    
    if (!allocator->disk_blocks || !allocator->free_list) {
        free(allocator->disk_blocks);
        free(allocator->free_list);
        free(allocator);
        return NULL;
    }

    // Initialize free list
    for (int i = 0; i < total_blocks; i++) {
        allocator->free_list[i] = i;
        allocator->disk_blocks[i].next_block = -1;
    }

    allocator->total_blocks = total_blocks;
    allocator->free_blocks = total_blocks;
    return allocator;
}

// Allocate a new block and link it
int allocate_linked_block(LinkedAllocator *allocator, int previous_block) {
    if (allocator->free_blocks == 0) return -1;

    int new_block = allocator->free_list[--allocator->free_blocks];
    
    if (previous_block != -1) {
        allocator->disk_blocks[previous_block].next_block = new_block;
    }

    allocator->disk_blocks[new_block].block_number = new_block;
    allocator->disk_blocks[new_block].next_block = -1;
    
    return new_block;
}

4.索引分配

索引分配使用索引块来存储所有文件数据块的指针。这种方法结合了连续分配和链接分配的优点,同时尽量减少了它们的缺点。

索引块包含磁盘块地址数组,允许直接访问文件中的任何块。这种方法支持顺序访问和随机访问高效地,但索引块会有一些空间开销。

#define INDEX_BLOCK_ENTRIES ((BLOCK_SIZE - sizeof(int)) / sizeof(int))

typedef struct IndexBlock {
    int num_entries;
    int block_pointers[INDEX_BLOCK_ENTRIES];
} IndexBlock;

typedef struct IndexedFile {
    int index_block;
    char name[256];
    size_t size;
} IndexedFile;

typedef struct IndexedAllocator {
    void *disk_blocks;
    IndexBlock *index_blocks;
    int total_blocks;
    int free_blocks;
    int *free_list;
} IndexedAllocator;

IndexedAllocator* init_indexed_allocator(int total_blocks) {
    IndexedAllocator *allocator = malloc(sizeof(IndexedAllocator));
    if (!allocator) return NULL;

    allocator->disk_blocks = malloc(total_blocks * BLOCK_SIZE);
    allocator->index_blocks = malloc(total_blocks * sizeof(IndexBlock));
    allocator->free_list = malloc(total_blocks * sizeof(int));

    if (!allocator->disk_blocks || !allocator->index_blocks || !allocator->free_list) {
        free(allocator->disk_blocks);
        free(allocator->index_blocks);
        free(allocator->free_list);
        free(allocator);
        return NULL;
    }

    // Initialize free list
    for (int i = 0; i < total_blocks; i++) {
        allocator->free_list[i] = i;
        allocator->index_blocks[i].num_entries = 0;
    }

    allocator->total_blocks = total_blocks;
    allocator->free_blocks = total_blocks;
    return allocator;
}

// Allocate an indexed file
IndexedFile* create_indexed_file(IndexedAllocator *allocator, const char *name) {
    if (allocator->free_blocks == 0) return NULL;

    IndexedFile *file = malloc(sizeof(IndexedFile));
    if (!file) return NULL;

    // Allocate index block
    file->index_block = allocator->free_list[--allocator->free_blocks];
    strncpy(file->name, name, 255);
    file->size = 0;

    // Initialize index block
    allocator->index_blocks[file->index_block].num_entries = 0;

    return file;
}

5.多级索引分配

多级索引分配扩展了索引分配方法,通过使用多个级别的索引块来实现。这种方法可以在保持合理访问时间的同时,有效处理非常大的文件。

主要索引块包含指向二级索引块的指针,而二级索引块又指向数据块。这种分层结构可以扩展到多个级别,类似于现代文件系统如 ext4 实现他们的 inode 结构。

#define DIRECT_BLOCKS 12
#define INDIRECT_BLOCKS ((BLOCK_SIZE - sizeof(struct MultiLevelIndex)) / sizeof(int))

typedef struct MultiLevelIndex {
    int direct[DIRECT_BLOCKS];          // Direct block pointers
    int single_indirect;                // Single indirect block pointer
    int double_indirect;                // Double indirect block pointer
    int triple_indirect;                // Triple indirect block pointer
    size_t file_size;
} MultiLevelIndex;

typedef struct IndirectBlock {
    int blocks[INDIRECT_BLOCKS];
} IndirectBlock;

typedef struct MultiLevelAllocator {
    void *disk_blocks;
    MultiLevelIndex *index_table;
    IndirectBlock *indirect_blocks;
    int total_blocks;
    int free_blocks;
    int *free_list;
} MultiLevelAllocator;

// Initialize multi-level allocator
MultiLevelAllocator* init_multilevel_allocator(int total_blocks) {
    MultiLevelAllocator *allocator = malloc(sizeof(MultiLevelAllocator));
    if (!allocator) return NULL;

    // Allocate all necessary structures
    allocator->disk_blocks = malloc(total_blocks * BLOCK_SIZE);
    allocator->index_table = malloc(total_blocks * sizeof(MultiLevelIndex));
    allocator->indirect_blocks = malloc(total_blocks * sizeof(IndirectBlock));
    allocator->free_list = malloc(total_blocks * sizeof(int));

    if (!allocator->disk_blocks || !allocator->index_table || 
        !allocator->indirect_blocks || !allocator->free_list) {
        // Cleanup and return on failure
        free(allocator->disk_blocks);
        free(allocator->index_table);
        free(allocator->indirect_blocks);
        free(allocator->free_list);
        free(allocator);
        return NULL;
    }

    // Initialize structures
    memset(allocator->index_table, 0, total_blocks * sizeof(MultiLevelIndex));
    for (int i = 0; i < total_blocks; i++) {
        allocator->free_list[i] = i;
    }

    allocator->total_blocks = total_blocks;
    allocator->free_blocks = total_blocks;
    return allocator;
}

// Get block address for given file offset
int get_block_address(MultiLevelAllocator *allocator, MultiLevelIndex *index, 
                     size_t block_number) {
    // Direct blocks
    if (block_number < DIRECT_BLOCKS) {
        return index->direct[block_number];
    }

    block_number -= DIRECT_BLOCKS;
    
    // Single indirect
    if (block_number < INDIRECT_BLOCKS) {
        IndirectBlock *indirect = &allocator->indirect_blocks[index->single_indirect];
        return indirect->blocks[block_number];
    }

    block_number -= INDIRECT_BLOCKS;

    // Double indirect
    if (block_number < INDIRECT_BLOCKS * INDIRECT_BLOCKS) {
        int indirect_index = block_number / INDIRECT_BLOCKS;
        int block_index = block_number % INDIRECT_BLOCKS;
        
        IndirectBlock *double_indirect = 
            &allocator->indirect_blocks[index->double_indirect];
        IndirectBlock *indirect = 
            &allocator->indirect_blocks[double_indirect->blocks[indirect_index]];
            
        return indirect->blocks[block_index];
    }

    // Triple indirect handling would go here...
    return -1;
}

6.基于范围的分配

基于范围的分配是一种现代方法,它结合了连续分配的好处以及其他方法的灵活性。一个范围是一系列连续的块,可以作为一个整体进行分配。

这种方法在保持良好性能特征的同时减少了碎片。它特别适用于大型文件,并在 ext4 和 XFS 等许多现代文件系统中使用。

typedef struct Extent {
    int start_block;
    int length;
    struct Extent *next;
} Extent;

typedef struct ExtentFile {
    char name[256];
    Extent *extent_list;
    size_t size;
    int extent_count;
} ExtentFile;

typedef struct ExtentAllocator {
    int *disk_blocks;
    int total_blocks;
    int free_blocks;
    ExtentFile *files;
    int max_files;
} ExtentAllocator;

// Initialize extent-based allocator
ExtentAllocator* init_extent_allocator(int total_blocks, int max_files) {
    ExtentAllocator *allocator = malloc(sizeof(ExtentAllocator));
    if (!allocator) return NULL;

    allocator->disk_blocks = calloc(total_blocks, sizeof(int));
    allocator->files = calloc(max_files, sizeof(ExtentFile));

    if (!allocator->disk_blocks || !allocator->files) {
        free(allocator->disk_blocks);
        free(allocator->files);
        free(allocator);
        return NULL;
    }

    allocator->total_blocks = total_blocks;
    allocator->free_blocks = total_blocks;
    allocator->max_files = max_files;

    return allocator;
}

// Allocate new extent
Extent* allocate_extent(ExtentAllocator *allocator, int desired_length) {
    int current_length = 0;
    int start_block = -1;

    // Find contiguous free blocks
    for (int i = 0; i < allocator->total_blocks; i++) {
        if (allocator->disk_blocks[i] == 0) {
            if (current_length == 0) start_block = i;
            current_length++;

            if (current_length == desired_length) {
                // Allocate the extent
                Extent *extent = malloc(sizeof(Extent));
                if (!extent) return NULL;

                extent->start_block = start_block;
                extent->length = current_length;
                extent->next = NULL;

                // Mark blocks as allocated
                for (int j = start_block; j < start_block + current_length; j++) {
                    allocator->disk_blocks[j] = 1;
                }
                allocator->free_blocks -= current_length;

                return extent;
            }
        } else {
            current_length = 0;
        }
    }

    return NULL;
}

7.混合分配方案

混合分配方案结合了多种分配方法,以利用各自的优点,同时尽量减少各自的缺点。这些方案通常用于现代文件系统,以优化处理不同类型的文件和访问模式。

例如,一种混合方案可能使用基于大小的文件分配对大文件使用延续分配法,对小文件使用直接块法,对中等大小的文件使用间接块法。这种方法提供了广泛的文件大小和访问模式下的良好性能。

typedef enum AllocationType {
    ALLOCATION_DIRECT,
    ALLOCATION_INDIRECT,
    ALLOCATION_EXTENT,
    ALLOCATION_MULTILEVEL
} AllocationType;

typedef struct HybridBlock {
    union {
        int direct_blocks[DIRECT_BLOCKS];
        MultiLevelIndex multilevel_index;
        Extent *extent_list;
        int *indirect_blocks;
    } data;
    AllocationType type;
} HybridBlock;

typedef struct HybridFile {
    char name[256];
    size_t size;
    HybridBlock block;
} HybridFile;

typedef struct HybridAllocator {
    void *disk_blocks;
    int total_blocks;
    int free_blocks;
    HybridFile *files;
    int max_files;
    size_t direct_threshold;    // Size threshold for direct allocation
    size_t extent_threshold;    // Size threshold for extent allocation
} HybridAllocator;

// Choose appropriate allocation method based on file size
AllocationType determine_allocation_type(HybridAllocator *allocator, size_t file_size) {
    if (file_size <= allocator->direct_threshold) {
        return ALLOCATION_DIRECT;
    } else if (file_size <= allocator->extent_threshold) {
        return ALLOCATION_EXTENT;
    } else {
        return ALLOCATION_MULTILEVEL;
    }
}

// Create new file with hybrid allocation
HybridFile* create_hybrid_file(HybridAllocator *allocator, 
                             const char *name, 
                             size_t initial_size) {
    if (allocator->free_blocks == 0) return NULL;

    HybridFile *file = malloc(sizeof(HybridFile));
    if (!file) return NULL;

    strncpy(file->name, name, 255);
    file->size = initial_size;
    
    AllocationType type = determine_allocation_type(allocator, initial_size);
    file->block.type = type;

    // Initialize based on allocation type
    switch (type) {
        case ALLOCATION_DIRECT:
            memset(file->block.data.direct_blocks, 0, 
                   sizeof(file->block.data.direct_blocks));
            break;
        case ALLOCATION_EXTENT:
            file->block.data.extent_list = 
                allocate_extent(allocator, 
                              (initial_size + BLOCK_SIZE - 1) / BLOCK_SIZE);
            break;
        case ALLOCATION_MULTILEVEL:
            // Initialize multilevel index
            memset(&file->block.data.multilevel_index, 0, 
                   sizeof(MultiLevelIndex));
            break;
    }

    return file;
}

8.动态块分配

动态块分配是指根据文件的大小和变化,按需分配和释放块。这种方法提供了灵活的管理存储空间,并在随时间推移帮助优化磁盘利用效率。

实现必须能够处理文件增长时新块的分配以及文件被删除或截断时块的正确释放。这需要对空闲空间和块跟踪进行仔细管理。

typedef struct DynamicAllocator {
    int *disk_blocks;
    int total_blocks;
    int free_blocks;
    struct {
        int *blocks;
        int count;
    } free_list;
    struct {
        int *blocks;
        int count;
    } recently_freed;  // For delayed reallocation
} DynamicAllocator;

// Initialize dynamic allocator
DynamicAllocator* init_dynamic_allocator(int total_blocks) {
    DynamicAllocator *allocator = malloc(sizeof(DynamicAllocator));
    if (!allocator) return NULL;

    allocator->disk_blocks = calloc(total_blocks, sizeof(int));
    allocator->free_list.blocks = malloc(total_blocks * sizeof(int));
    allocator->recently_freed.blocks = malloc(total_blocks * sizeof(int));

    if (!allocator->disk_blocks || !allocator->free_list.blocks || 
        !allocator->recently_freed.blocks) {
        free(allocator->disk_blocks);
        free(allocator->free_list.blocks);
        free(allocator->recently_freed.blocks);
        free(allocator);
        return NULL;
    }

    // Initialize free list
    for (int i = 0; i < total_blocks; i++) {
        allocator->free_list.blocks[i] = i;
    }
    allocator->free_list.count = total_blocks;
    allocator->recently_freed.count = 0;
    allocator->total_blocks = total_blocks;
    allocator->free_blocks = total_blocks;

    return allocator;
}

// Allocate blocks dynamically
int* allocate_blocks(DynamicAllocator *allocator, int count) {
    if (count > allocator->free_blocks) return NULL;

    int *allocated = malloc(count * sizeof(int));
    if (!allocated) return NULL;

    for (int i = 0; i < count; i++) {
        // Prefer recently freed blocks for better locality
        if (allocator->recently_freed.count > 0) {
            allocated[i] = allocator->recently_freed.blocks[--allocator->recently_freed.count];
        } else {
            allocated[i] = allocator->free_list.blocks[--allocator->free_list.count];
        }
        allocator->disk_blocks[allocated[i]] = 1;
        allocator->free_blocks--;
    }

    return allocated;
}

9.块大小优化

块大小优化涉及为文件系统选择适当的块大小,并实施机制以高效地处理不同块大小。块大小的选择会影响存储效率和性能。

较大的块减少了块管理开销,提高了顺序访问性能,而较小的块减少了内部碎片。现代文件系统通常支持多个块大小,或对小文件实施块子分配。

typedef struct BlockSizeManager {
    int standard_block_size;
    int sub_block_size;
    int blocks_per_group;
    struct {
        void *data;
        int *bitmap;
        int total_sub_blocks;
        int free_sub_blocks;
    } *sub_block_groups;
    int group_count;
} BlockSizeManager;

// Initialize block size manager
BlockSizeManager* init_block_size_manager(int std_size, int sub_size, int groups) {
    BlockSizeManager *manager = malloc(sizeof(BlockSizeManager));
    if (!manager) return NULL;

    manager->standard_block_size = std_size;
    manager->sub_block_size = sub_size;
    manager->blocks_per_group = std_size / sub_size;
    manager->group_count = groups;

    manager->sub_block_groups = malloc(groups * sizeof(*manager->sub_block_groups));
    if (!manager->sub_block_groups) {
        free(manager);
        return NULL;
    }

    // Initialize each group
    for (int i = 0; i < groups; i++) {
        manager->sub_block_groups[i].data = malloc(std_size);
        manager->sub_block_groups[i].bitmap = calloc(
            manager->blocks_per_group, 
            sizeof(int)
        );
        manager->sub_block_groups[i].total_sub_blocks = manager->blocks_per_group;
        manager->sub_block_groups[i].free_sub_blocks = manager->blocks_per_group;

        if (!manager->sub_block_groups[i].data || 
            !manager->sub_block_groups[i].bitmap) {
            // Cleanup on failure
            for (int j = 0; j <= i; j++) {
                free(manager->sub_block_groups[j].data);
                free(manager->sub_block_groups[j].bitmap);
            }
            free(manager->sub_block_groups);
            free(manager);
            return NULL;
        }
    }

    return manager;
}

// Allocate appropriate block size
void* allocate_optimal_block(BlockSizeManager *manager, size_t size) {
    if (size <= manager->sub_block_size) {
        // Allocate sub-block
        for (int i = 0; i < manager->group_count; i++) {
            if (manager->sub_block_groups[i].free_sub_blocks > 0) {
                // Find free sub-block
                for (int j = 0; j < manager->blocks_per_group; j++) {
                    if (!manager->sub_block_groups[i].bitmap[j]) {
                        manager->sub_block_groups[i].bitmap[j] = 1;
                        manager->sub_block_groups[i].free_sub_blocks--;
                        return (char*)manager->sub_block_groups[i].data + 
                               (j * manager->sub_block_size);
                    }
                }
            }
        }
    }
    
    // Allocate standard block
    return malloc(manager->standard_block_size);
}

10.碎片管理

碎片管理涉及实施策略以防止、检测和处理内部和外部碎片。这对于在一段时间内保持高效的存储利用至关重要。

系统必须实施预防性措施以最小化碎片化和在必要时实施修复性措施(如磁盘碎片整理)来优化存储布局。

typedef struct FragmentationManager {
    struct {
        int total_space;
        int used_space;
        int largest_free_block;
        double fragmentation_ratio;
    } metrics;
    
    struct {
        int block_start;
        int block_length;
    } *free_regions;
    
    int region_count;
    int total_blocks;
} FragmentationManager;

// Initialize fragmentation manager
FragmentationManager* init_fragmentation_manager(int total_blocks) {
    FragmentationManager *manager = malloc(sizeof(FragmentationManager));
    if (!manager) return NULL;

    manager->free_regions = malloc(total_blocks * sizeof(*manager->free_regions));
    if (!manager->free_regions) {
        free(manager);
        return NULL;
    }

    manager->metrics.total_space = total_blocks;
    manager->metrics.used_space = 0;
    manager->metrics.largest_free_block = total_blocks;
    manager->metrics.fragmentation_ratio = 0.0;
    manager->region_count = 1;
    manager->total_blocks = total_blocks;

    // Initialize with one free region
    manager->free_regions[0].block_start = 0;
    manager->free_regions[0].block_length = total_blocks;

    return manager;
}

// Calculate fragmentation metrics
void update_fragmentation_metrics(FragmentationManager *manager) {
    int largest_free = 0;
    int total_free = 0;
    double weighted_fragmentation = 0.0;

    for (int i = 0; i < manager->region_count; i++) {
        int region_size = manager->free_regions[i].block_length;
        total_free += region_size;
        if (region_size > largest_free) {
            largest_free = region_size;
        }
        
        // Weight smaller fragments more heavily
        weighted_fragmentation += (double)region_size / 
                                (double)manager->total_blocks * 
                                (1.0 - (double)region_size / 
                                      (double)manager->total_blocks);
    }

    manager->metrics.largest_free_block = largest_free;
    manager->metrics.used_space = manager->total_blocks - total_free;
    manager->metrics.fragmentation_ratio = weighted_fragmentation;
}

// Defragmentation algorithm
void defragment(FragmentationManager *manager) {
    // Sort free regions by start block
    for (int i = 0; i < manager->region_count - 1; i++) {
        for (int j = 0; j < manager->region_count - i - 1; j++) {
            if (manager->free_regions[j].block_start > 
                manager->free_regions[j + 1].block_start) {
                // Swap regions
                struct {
                    int block_start;
                    int block_length;
                } temp = manager->free_regions[j];
                manager->free_regions[j] = manager->free_regions[j + 1];
                manager->free_regions[j + 1] = temp;
            }
        }
    }

    // Merge adjacent regions
    int write_idx = 0;
    for (int read_idx = 1; read_idx < manager->region_count; read_idx++) {
        if (manager->free_regions[write_idx].block_start + 
            manager->free_regions[write_idx].block_length == 
            manager->free_regions[read_idx].block_start) {
            // Merge regions
            manager->free_regions[write_idx].block_length += 
                manager->free_regions[read_idx].block_length;
        } else {
            // Move to next region
            write_idx++;
            manager->free_regions[write_idx] = manager->free_regions[read_idx];
        }
    }
    manager->region_count = write_idx + 1;
}

11.性能优化

文件分配中的性能优化涉及实施策略,以提高读取和写入速度,同时保持高效的空间利用。这包括预取、缓存和智能块放置等技术。

实施必须平衡不同的性能指标,如顺序访问速度、随机访问性能和空间效率。现代系统通常使用预测算法来优化块的放置和访问模式。

typedef struct PerformanceOptimizer {
    struct {
        int *blocks;
        int count;
        int capacity;
    } prefetch_queue;
    
    struct {
        int *block_access_count;
        int *block_access_pattern;
        double *block_heat_map;
    } metrics;
    
    int total_blocks;
    int prefetch_window_size;
} PerformanceOptimizer;

// Initialize performance optimizer
PerformanceOptimizer* init_performance_optimizer(int total_blocks, int prefetch_size) {
    PerformanceOptimizer *optimizer = malloc(sizeof(PerformanceOptimizer));
    if (!optimizer) return NULL;

    optimizer->prefetch_queue.blocks = malloc(prefetch_size * sizeof(int));
    optimizer->metrics.block_access_count = calloc(total_blocks, sizeof(int));
    optimizer->metrics.block_access_pattern = calloc(total_blocks, sizeof(int));
    optimizer->metrics.block_heat_map = calloc(total_blocks, sizeof(double));

    if (!optimizer->prefetch_queue.blocks || 
        !optimizer->metrics.block_access_count ||
        !optimizer->metrics.block_access_pattern || 
        !optimizer->metrics.block_heat_map) {
        // Cleanup on failure
        free(optimizer->prefetch_queue.blocks);
        free(optimizer->metrics.block_access_count);
        free(optimizer->metrics.block_access_pattern);
        free(optimizer->metrics.block_heat_map);
        free(optimizer);
        return NULL;
    }

    optimizer->prefetch_queue.capacity = prefetch_size;
    optimizer->prefetch_queue.count = 0;
    optimizer->total_blocks = total_blocks;
    optimizer->prefetch_window_size = prefetch_size;

    return optimizer;
}

// Update access patterns and trigger prefetch
void update_access_pattern(PerformanceOptimizer *optimizer, int block_number) {
    // Update access count
    optimizer->metrics.block_access_count[block_number]++;
    
    // Update heat map with decay
    const double decay_factor = 0.95;
    for (int i = 0; i < optimizer->total_blocks; i++) {
        optimizer->metrics.block_heat_map[i] *= decay_factor;
    }
    optimizer->metrics.block_heat_map[block_number] += 1.0;

    // Predict next blocks to prefetch
    int predicted_blocks[MAX_PREFETCH];
    int predict_count = predict_next_blocks(optimizer, block_number, predicted_blocks);
    
    // Queue prefetch operations
    for (int i = 0; i < predict_count; i++) {
        queue_prefetch(optimizer, predicted_blocks[i]);
    }
}

12.恢复和一致性

恢复和一致性机制确保即使在系统崩溃或断电的情况下,文件系统也能保持一致状态。这包括实现日志记录、校验和和恢复程序。

实现必须同时处理元数据和数据一致性,提供机制以检测和恢复从损坏中恢复,同时保持可接受的性能水平。

typedef struct RecoveryManager {
    struct {
        int transaction_id;
        int block_number;
        void *old_data;
        void *new_data;
        int data_size;
    } *journal_entries;
    
    int journal_capacity;
    int journal_count;
    int checkpoint_interval;
    time_t last_checkpoint;
} RecoveryManager;

// Initialize recovery manager
RecoveryManager* init_recovery_manager(int journal_size, int checkpoint_interval) {
    RecoveryManager *manager = malloc(sizeof(RecoveryManager));
    if (!manager) return NULL;

    manager->journal_entries = malloc(journal_size * 
                                    sizeof(*manager->journal_entries));
    if (!manager->journal_entries) {
        free(manager);
        return NULL;
    }

    manager->journal_capacity = journal_size;
    manager->journal_count = 0;
    manager->checkpoint_interval = checkpoint_interval;
    manager->last_checkpoint = time(NULL);

    return manager;
}

// Log a transaction
int log_transaction(RecoveryManager *manager, int block_num, 
                   void *old_data, void *new_data, int size) {
    if (manager->journal_count >= manager->journal_capacity) {
        // Force checkpoint if journal is full
        create_checkpoint(manager);
    }

    int entry_idx = manager->journal_count++;
    manager->journal_entries[entry_idx].transaction_id = entry_idx;
    manager->journal_entries[entry_idx].block_number = block_num;
    
    manager->journal_entries[entry_idx].old_data = malloc(size);
    manager->journal_entries[entry_idx].new_data = malloc(size);
    
    if (!manager->journal_entries[entry_idx].old_data || 
        !manager->journal_entries[entry_idx].new_data) {
        return -1;
    }

    memcpy(manager->journal_entries[entry_idx].old_data, old_data, size);
    memcpy(manager->journal_entries[entry_idx].new_data, new_data, size);
    manager->journal_entries[entry_idx].data_size = size;

    return entry_idx;
}

13.最佳实践和指南

在实施文件分配方法时,应考虑以下关键指导原则:

  • 始终实现适当的错误处理和恢复机制
  • 根据文件大小和访问模式使用适当的分配策略
  • 实现有效的免费空间管理
  • 定期进行磁盘碎片整理和优化
  • 通过日志记录保持一致性
  • 监控和优化性能指标
  • 实现对于并发访问的适当锁机制
  • 定期进行和恢复测试

14.总结

文件分配方法对文件系统的性能和可靠性是基本且重要的。选择分配方法取决于各种因素,包括:

  • 预期文件大小和访问模式
  • 性能要求
  • 存储设备特性
  • 可靠性要求
  • 系统资源

现代文件系统通常采用混合方法,结合多种分配方法,以在不同使用案例中实现最优性能。